Efficient way to update multiple fields of Django model object

Even simpler if you use .update() method of QuerySet object as:

my_id = fetched_data.pop('id')  # remove 'id' from `fetch_data`
                                # as it is not supposed to be updated

User.objects.filter(pk=my_id).update(**fetched_data)
#          unpack the content of `dict` ^

It will unpack the content of fetched_data dict and will update the records in User object whose columns are present as key to the fetched_data dict. Since you are calling filter on pk, it will always return single record.


You can update a row in the database without fetching and deserializing it; update() can do it. E.g.:

User.objects.filter(id=data['id']).update(email=data['email'], phone=data['phone'])

This will issue one SQL update statement, and is much faster than the code in your post. It will never fetch the data or waste time creating a User object.

You cannot, though, send a whole bunch of update data to the SQL database and ask it to map it to different rows in one go. If you need a massive update like that done very quickly, your best bet is probably inserting the data into a separate table and then update it form a select on that table. Django ORM does not support this, as far as I can tell.


If you use .update then there is an issue, since it won't raise post_save or pre_save signal, so if you want to use any signal on any change of data then User.objects.filter(pk=fetched_data['id']).update(**kwargs) won't work.

So you can use setattr() to update the fields and then .save would save the row which would update the row also raise an signal.

old_user = User.objects.get(pk=fetched_data['id'])
for key, value in fetched_data.iteritems():
    setattr(old_user, key, value)
old_user.save()

setattr(old_user, fetched_data_key, fetched_data['fetched_data_key'])

Tags:

Python

Django