Reputation: 12064
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
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
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
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
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
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
Reputation: 36033
setattr(old_user, fetched_data_key, fetched_data['fetched_data_key'])
Upvotes: 6