You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

除已知场景外,Django中select_for_update()不生效但print(qs)生效的其他情况

Django中select_for_update()不生效但print(qs)后生效的其他场景

模型定义

# "store/models.py"
from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=30)

已知案例

案例1:QuerySet.update()链式调用

  • 直接链式调用:Person.objects.select_for_update().update(name="Tom")仅执行UPDATE语句,无SELECT FOR UPDATE锁查询。
  • 拆分并加入print:
    qs = Person.objects.select_for_update()
    print(qs)  # 触发QuerySet求值,执行SELECT FOR UPDATE
    qs.update(name="Tom")  # 执行UPDATE语句
    
    此时会先后执行SELECT FOR UPDATE和UPDATE两种查询。
  • 与对象save()结合:先通过select_for_update()获取对象,再调用save(),会正常执行SELECT FOR UPDATE和UPDATE查询。

案例2:QuerySet.delete()链式调用

  • 直接链式调用:Person.objects.select_for_update().delete()仅执行DELETE语句,无SELECT FOR UPDATE锁查询。
  • 拆分并加入print:
    qs = Person.objects.select_for_update()
    print(qs)  # 触发QuerySet求值,执行SELECT FOR UPDATE
    qs.delete()  # 执行DELETE语句
    
    此时会先后执行SELECT FOR UPDATE和DELETE两种查询。
  • 与对象delete()结合:先通过select_for_update()获取对象,再调用delete(),会正常执行SELECT FOR UPDATE和DELETE查询。

其他符合条件的场景

以下场景中,直接链式调用select_for_update()与对应QuerySet方法时,select_for_update()不会生效;但提前通过print(qs)触发QuerySet求值后,会先执行SELECT FOR UPDATE锁查询,再执行目标操作:

  • QuerySet.bulk_create()批量插入

    • 直接调用:Person.objects.select_for_update().bulk_create([Person(name="Alice"), Person(name="Bob")])仅执行批量INSERT语句,无锁查询。
    • 拆分加print后:先执行SELECT FOR UPDATE锁定匹配行,再执行批量插入。
  • QuerySet.bulk_update()批量更新

    • 直接调用:
      persons = Person.objects.filter(name__startswith="A")
      for p in persons:
          p.name = p.name + "_updated"
      Person.objects.select_for_update().bulk_update(persons, ["name"])
      
      仅执行批量UPDATE语句,无锁查询。
    • 拆分加print后:先执行SELECT FOR UPDATE锁定匹配行,再执行批量更新。
  • QuerySet.exists()存在性检查

    • 直接调用:Person.objects.select_for_update().exists()仅执行EXISTS查询,不会锁定任何行。
    • 拆分加print后:先执行SELECT FOR UPDATE锁定匹配行,再执行EXISTS检查。
  • QuerySet.count()统计数量

    • 直接调用:Person.objects.select_for_update().count()仅执行COUNT聚合查询,无锁查询。
    • 拆分加print后:先执行SELECT FOR UPDATE锁定匹配行,再统计行数。
  • QuerySet.aggregate()聚合计算

    • 直接调用:Person.objects.select_for_update().aggregate(total=Count('id'))仅执行聚合查询,无锁查询。
    • 拆分加print后:先执行SELECT FOR UPDATE锁定匹配行,再执行聚合计算。

内容的提问来源于stack exchange,提问作者Super Kai - Kazuya Ito

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 13:31:04