Update a field of a Django Object

Tags: , , ,



I’m trying to update an object field in django. Usually I would do something like this:

# MODEL ---
class MyObj(models.model):
    name: models.CharField(max_length=10)
    surname: models.CharField(max_length=10)

# VIEW ---
# [...]
   myObj = MyObj.objects.get(pk=1)
   myObj.name = 'John'
   myObj.save() 

The problem is that the field to modify (in the example above: “name”) is not known and passed as an argument to the post request. So I would have something like this:

# VIEW ---
# [...]
   field = self.request.query_params['field_to_modify']

   myObj = MyObj.objects.get(pk=1)
   myObj[field] = 'John'
   myObj.save() 

now this triggers the error:

myObj[field] = 'John'
TypeError: 'MyObj' object does not support item assignment

What is the correct way to update an “unknown” field of a django object?

UPDATE

Thank you for your answers so far! OK so the way to go is apparently using setattr (as per the answers). Now the problem is that it does not allow me to save the modified object without checking if it is valid.

So I tried using the Serializer to check the object validity but is not working:

field = self.request.query_params['field_to_modify']
myObj = MyObj.objects.get(pk=1)
setattr(myObj, field, 'John')
serial = MyObjSerializer(myObj)
serial.is_valid(raise_exception=True)
serial.save()

error:

AssertionError: Cannot call `.is_valid()` as no `data=` keyword argument was passed when instantiating the serializer instance.

Answer

You’re looking for setattr to set an attribute by name.

field = self.request.query_params['field_to_modify']
# TODO: add validation for `field`
myObj = MyObj.objects.get(pk=1)
setattr(myObj, field, 'John')
myObj.save(update_fields=[field])  # no need to update anything but the single field

Of course, this won’t let you automatically attach any arbitrary data to models and expect it to be saved; if you need something like that, maybe use a JSON field.

EDIT:

For using a Django REST Framework serializer (which, cough, wasn’t part of the original question or tags, but could be inferred from query_params), one could do

field = self.request.query_params['field_to_modify']
myObj = MyObj.objects.get(pk=1)
serial = MyObjSerializer(instance=myObj, data={field: 'John'})
serial.is_valid(raise_exception=True)
serial.save()


Source: stackoverflow