Updating selection of objects, each with a different value in bulk (Django)

核能气质少年 提交于 2019-12-30 04:20:27

问题


Imagine I have a python dictionary where keys are existing user ids, and values are scores to be added to those users' existing scores.

For example: {1: 1580, 4: 540, 2: 678} (this could stretch to n k,v pairs)

I need to update the scores of all these user objects (updated_score = original_score + new_score). One way to do it is iteratively, like so:

from django.db.models import F
scores = {1: 1580, 4: 540, 2: 678}
for user_id,score_to_add in scores.iteritems():
    UserProfile.objects.filter(user_id=user_id).update(score=F('score')+score_to_add)

But that's multiple DB calls. Can I do it in a single call? An illustrative example would be great. As you would have guessed, this is for a Django project.


回答1:


Something like that:

from django.db.models import F
from django.db import transaction

with transaction.atomic():
    scores = {1: 1580, 4: 540, 2: 678}
    for user_id,score_to_add in scores:
        UserProfile.objects.filter(user_id=user_id).update(score=F('score')+score_to_add)

More on this here

You can take a look at this answer too.

[UPDATE]:

TL;DR: It'll not make one db query but it will be faster cause each query lacks the database overhead.

As the docs and @ahmed in his answer say:

Django’s default behavior is to run in autocommit mode. Each query is immediately committed to the database, unless a transaction is active.

By using with transaction.atomic() all the inserts are grouped into a single transaction. The time needed to commit the transaction is amortized over all the enclosed insert statements and so the time per insert statement is greatly reduced.




回答2:


transaction.atomic() proposed by @nik_m is good idea, but also you should get records from database in single request.

from django.db.models import F
from django.db import transaction

with transaction.atomic():
    scores = {1: 1580, 4: 540, 2: 678}
    users_to_update = UserProfile.objects.filter(
        user_id__in=scores.keys()
    ) 
    for user in users_to_update:
        user.update(score=F('score') + scores[user.user_id])


来源:https://stackoverflow.com/questions/42732939/updating-selection-of-objects-each-with-a-different-value-in-bulk-django

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!