Efficient way to update multiple fields of Django model object
Question:
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?
Answers:
setattr(old_user, fetched_data_key, fetched_data['fetched_data_key'])
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()
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})
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?
setattr(old_user, fetched_data_key, fetched_data['fetched_data_key'])
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()
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})