django F查询

F查询

使用 F() 避免竞争条件

F() 可以通过以下方式提供性能优势:

  • 让数据库,而不是 Python 来完成工作, 避免了 竞争条件
  • 减少某些操作所需的查询次数

如果两个 Python 线程执行修改一个字段的值的代码,一个线程可以在另一个线程从数据库中获取一个字段的值后,检索、递增并保存它。第二个线程保存的值将基于原始值,第一个线程的工作将丢失。

如果数据库负责更新字段,那么这个过程就比较稳健:它只会在执行 save()update() 时,根据数据库中字段的值来更新字段,而不是根据检索实例时的值来更新。

F() 赋值在 Model.save() 之后持续存在

F() 分配给模型字段的对象在保存模型实例后会持续存在,并将应用于每个 save()。例如:

obj = Book.objects.get(pk=12)
print(obj.price)  # 10
obj.price = F('price') + 1
obj.save()
obj.name = '福尔摩5'
obj.save()  # 此时数据库里的price已经是12了

在这种情况下,stories_filed 将被更新两次。如果最初是 1,最终值将是 3。这种持久性可以通过在保存模型对象后重新加载来避免,例如,使用 refresh_from_db()

F对时间加减

对于 date 和 date/time 字段,你可以加上或减去一个 timedelta对象。以下会返回所有发布 3 天后被修改的条目:

>>> from datetime import timedelta
>>> Entry.objects.filter(mod_date__gt=F('pub_date') + timedelta(days=3))

查找Entry在上次修改的同一年发布的所有对象:

>>> Entry.objects.filter(pub_date__year=F('mod_date__year'))

与annotate一起使用F()

F() 可用于通过将不同的字段与算术相结合,在你的模型上创建动态字段:

company = Company.objects.annotate(
    chairs_needed=F('num_employees') - F('num_chairs'))

如果你要组合的字段是不同类型的,你需要告诉 Django 将返回什么样的字段。由于 F() 不直接支持 output_field,你需要用[ExpressionWrapper来包装表达式:

from django.db.models import DateTimeField, ExpressionWrapper, F

Ticket.objects.annotate(
    expires=ExpressionWrapper(
      	# 活动时间          持续时间
        F('active_at') + F('duration'), output_field=DateTimeField()))
posted @ 2023-01-10 11:14  zong涵  阅读(132)  评论(0编辑  收藏  举报