53

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?

5 Answers 5

73

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.

Sign up to request clarification or add additional context in comments.

3 Comments

When creating an object I know you can do something like e = User(**data). Would this work for update?
@DjangoBlockchain: It may, but it will defeat the purpose of this answer. The idea is to not create an ORM model object for each DB record you want to update. It really kills performance.
I ended up doing User.objects.filter(id=data['id']).update(**data), so it just updates every field instead of specifying individual fields. Sorry if my question was confusing.
34

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.

6 Comments

what if I need to update only one object from the queryset?
"pk" is the unique key in your Django model. On filtering based on it will return you a QuerySet containing only one object.
the problem is I am not using 'pk'
@brainLoop : By default "pk" references the primary key column of your Django model.
@Anonymous I did exactly the same as you explained. The record is updated but my updated_at (auto_now) field is not getting updated. Maybe because we are not doing Obj.save().
|
19

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

1 Comment

This is by far the best way to go. Signals are all over the place in all medium and large Django projects; you wouldn't want to tinker with them
6
setattr(old_user, fetched_data_key, fetched_data['fetched_data_key'])

Comments

-1

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

1 Comment

Hi and welcome to Stack Overflow! Please take the tour. Thanks for contributing an answer but can you also add an explanation on how your code solves the problem? If you need help with formatting, see the help center.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.