Django中无需for循环更新Queryset实现order字段批量赋值
解决方案
分两种场景处理,都可以通过Django ORM的批量操作实现,不需要循环逐条save。
场景1:新建对象时更新已有对象order
你每次新建对象时,不需要全表重新计算所有order,直接对已有记录做批量+1即可,单条SQL执行,效率极高:
from django.db.models import F # 第一步:所有已有对象的order字段统一+1 Temporal.objects.update(order=F("order") + 1) # 第二步:创建新对象,order设为0 new_item = Temporal.objects.create(name="你的对象名", order=0)
这个方案每次新建只执行2次SQL,不管数据量多大都不会变慢。
场景2:全量重新计算所有对象的order值
如果你需要一次性给所有历史数据按created_at倒序重新赋值order,可以用Window窗口函数配合bulk_update实现,相比循环逐条save速度提升几个数量级:
from django.db.models import F, Window from django.db.models.functions import RowNumber # 用窗口函数直接在数据库层面计算每个对象的order值 items = Temporal.objects.annotate( calculated_order=Window( expression=RowNumber(), order_by=F('created_at').desc() ) ) # 批量更新字段,仅执行两次SQL(一次查,一次批量更新) Temporal.objects.bulk_update( [Temporal(id=item.id, order=item.calculated_order) for item in items], fields=['order'], batch_size=1000 )
注:Django 2.0及以上版本都支持窗口函数,batch_size可以根据你的数据库性能调整,数据量上万的话设为2000~5000都可以。
原方案慢的原因
你原来的for循环实现每一条数据都要单独执行一次UPDATE SQL,几千条数据就要执行几千次数据库请求,自然会很慢,上述方案都是尽量把计算逻辑放到数据库侧,减少请求次数,性能提升非常明显。
内容的提问来源于stack exchange,提问作者Lmex89
相关产品推荐
相关产品推荐

