I can make a new django model object with Model(**dictionary)
but if I want to update an instance in the same way, I've found only update_or_create
which has its problems and often returns 'duplicate PK' errors. It also doesn't seem particularly pythonic to call a custom helper function on a model object. Alternatively, you can use this pattern:
Model.objects.get(id=id).update(**dict)
or
model.__dict__.update(**dict)
model.save()
The latter feels like a hack and I read a few times that it's not 'supposed' to be done this way. The first method requires a query call and again feels incorrect since the model instance is likely already instantiated and to update it we need to send a query to the DB again?
I also read that 'you can do this with a form' - but its not always users that are updating models in the DB, there are all kinds of functions we might write which requires models to be updated. I wonder, is there a reason that the below code is not possible/implemented? Is there a reason that model objects are not directly callable and updateable in this way?
model_instance(**dict)
model_instance.save()
Model instances [Django docs] do not have any built-in methods which update the field values by feeding in keyword arguments.
update()
The following query will update the database row immediately, but has the disadvantage that it won't call any pre-save or post-save signals [Django docs] that you may have registered to the model:
Model.objects.filter(id=model_instance.id).update(**dict_)
And as you mentioned, if you intend to keep using the same instance you would need to update its values from the database:
model_instance.refresh_from_db()
model_instance(**dict_)
doesn't workDjango model instances (objects) are not callable. Objects cannot be called like functions by default. For example, when you create a plain dict dict_ = dict()
, you can't update it by calling dict_(**kwargs)
. An object can be made callable by overriding the __call__
[Python docs] class method.
update()
method on modelYou could create your own model method so you're only making one database call (and preserving signals). For example you could create an abstract base class [Django docs] that all of your models inherit from (rather than from models.Model
) e.g.
class ModelWithUpdate(models.Model):
class Meta:
abstract = True
def update(self, commit=False, **kwargs):
for key, value in kwargs.items():
setattr(self, key, value)
if commit:
self.save()
And then your usage would be:
model_instance.update(**dict_)
model_instance.save()
# or a shortcut
model_instance.update(commit=True, **dict_)