Boky
Boky

Reputation: 12064

Efficient way to update multiple fields of Django model object

I'm trying to update user in Django database.

Fetched data is as follows :

fetched_data = {
     'id': 1,
     'first_name': 'John',
     'last_name': 'Doe',
     'phone': '+32 12',
     'mobile_phone': '+32 13',
     'email': '[email protected]',
     'username': 'myusername'
}

I get the user with this id as follows :

old_user = User.objects.get(pk=fetched_data['id'])

If I update the user as follows :

old_user.username = fetched_data['username']
old_user.first_name = fetched_data['first_name']
......
old_user.save()

it works fine, but I do not want to do it for every record, thus I tried something like :

for fetched_data_key in fetched_data:
    old_user.fetched_data_key = fetched_data['fetched_data_key']
    //old_user[fetched_data_key] = fetched_data['fetched_data_key'] --- I tried this way to
    old_user.save()

But that doesn't work. Any idea how can I update the user without doing it for every record?

Upvotes: 53

Views: 61509

Answers (6)

frfahim
frfahim

Reputation: 525

User.objects.filter(pk=fetched_data['id']).update(**kwargs)

this will update multiple fields. But it won't call signals, So if there is any signal written for this model then it will not run.

So better to use setattr() method to set new data into the fields, then call .save() method and it will run the signal also.

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

Upvotes: 1

Simran Thakur
Simran Thakur

Reputation: 11

Blackquotes

def update_block(request, id):

a = RentedNumberBlock.objects.get(id=id)
b = RentedNumber.objects.filter(user=request.user)
c = a.rented_number.values_list('id', flat=True)
if request.POST:
    update = RentedNumberBlock.objects.get(id=id)
    update.name = request.POST['name']
    z = dict(request.POST)['rented_number']
    y = RentedNumber.objects.filter(id__in=z)
    update.rented_number.set(z)
    update.save()
    return HttpResponseRedirect('/block/')
return render(request, "block/update.html", {"a": a , "b": b, "c": c})

Upvotes: -1

Arghya Saha
Arghya Saha

Reputation: 5713

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()

Upvotes: 19

Moinuddin Quadri
Moinuddin Quadri

Reputation: 48077

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.

Upvotes: 34

9000
9000

Reputation: 40894

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.

Upvotes: 72

Alex Hall
Alex Hall

Reputation: 36033

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

Upvotes: 6

Related Questions