1

I have a model class which has an attribute that refers to django DB objects. I would like to change this attribute using a single view with setattr() which I use to make changes to any attributes for this object.

The problem is, I can't seem to pass an object instance through the stack. I'm not sure if I can even use setattr() for this. Actually I'm not even sure if the problem is with my attempted use of setattr() or something else - please let me know!

Error on POST attempt:

ValueError at /dollhouseupdate/1
Cannot assign "u'Citadel'": "Dollhouse.dh_background" must be a "Background" instance.

Model:

class Dollhouse(models.Model):
    dollhouse_name = models.CharField(max_length=100)
    user = models.ForeignKey(User)
    dh_background = models.ForeignKey(Background)
    def __str__(self):
        return self.dollhouse_name

Template:

    <select id="background-select">
      <option value="null">Change Background</option>
        {% for background in background_objects %}
        <option value="{{ background }}">{{ background.bg_name }} </option>
        {% endfor %}
    </select>

View:

def dollhouseupdate(request, dollhouseid):
    if request.method == 'POST':
        workingdollhouse = Dollhouse.objects.get(id=dollhouseid)
        if request.POST.get('erase') == "true":
            workingdollhouse.delete()
            return HttpResponse("Dollhouse deleted!")
        else:
            data = (request.POST).dict()
            for key, value in data.items():
                setattr(workingdollhouse, key, value)
            workingdollhouse.save()
            return HttpResponse("Dollhouse {} saved!".format(workingdollhouse.dollhouse_name))

Javascript:

//change dollhouse background
$("#background-select").change(function() {
    if($("#background-select").val() != null) {
        var dollhouseid = workingDollhouse;
        var dh_background = $("#background-select").val()
        console.log("changing background to " + dh_background);
        $.ajax("http://127.0.0.1:8000/dollhouseupdate/"+dollhouseid, {
            type: 'POST',
            data: {
                dh_background: dh_background,
            }
        })
        .done(function(response){
           console.log("The request is complete!");
           console.log(response);
           window.location = "http://127.0.0.1:8000/";
       })
       .fail(function() {
           console.log("Sorry, there was a problem!");
       })
    };
});
Selcuk
  • 57,004
  • 12
  • 102
  • 110
Catma
  • 39
  • 1
  • 9

2 Answers2

0

You are passing the object id in the POST variable, not the actual object itself (you can't do it anyway). Either change the following part

data: {
    dh_background: dh_background,
}

to

data: {
    dh_background_id: dh_background,
}

or get the object instance using the id in your view code.

Selcuk
  • 57,004
  • 12
  • 102
  • 110
  • Thank you, this is the simplest answer and preserves the use of setattr() for all attributes. I had previously tried this using "dh_background.id" instead of "dh_background_id" and it didn't update correctly. – Catma Nov 29 '16 at 02:50
0

As the error says, the Dollhouse.dh_background attribute must be an instance of the Background model. You are attempting to set its value to an object of a different type; I think a text string.

type(u'Citadel') is Background  # False

Instead, you'll need to put some smarts into the view so that Background instances are retrieved by whatever key you have; then, set the Dollhouse.dh_background attribute to that instance.

if name == 'background':
    background_code = post_args[name]
    background = Background.objects.get(code=background_code)
    workingdollhouse.dh_background = background

Because different POST arguments will refer to different fields, you will need to know what each one refers to and treat them differently. A simple “setattr for each one” won't work.

bignose
  • 30,281
  • 14
  • 77
  • 110