FreezeJ' Blog

Django F与Q

2022-08-17

F表达式

Django 使用 F() 对象来生成一个 SQL 表达式,在数据库层面描述所需的操作。
官方文档:https://docs.djangoproject.com/zh-hans/3.2/ref/models/expressions/#django.db.models.F

读取数据并在内存操作:

reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed += 1
reporter.save()

使用F表达式,使用引用的方式,通过数据库语句实现

from django.db.models import F

reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()

优化update语句:

reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') + 1)

# 或
Reporter.objects.all().update(stories_filed=F('stories_filed') + 1)

保存后刷新

F() 赋值在 Model.save() 之后持续存在,n次save会产生n次效果,需要刷新数据

reporter = Reporters.objects.get(pk=reporter.pk)
reporter.refresh_from_db()

在聚合中使用F

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

使用F表达式的优势:

  • 让数据库,而不是 Python 来完成工作
  • 减少某些操作所需的查询次数

Q表达式

Django 使用 Q() 对象表示一个 SQL 条件,它可以用于数据库相关的操作。
官方文档:https://docs.djangoproject.com/zh-hans/3.2/topics/db/queries/#complex-lookups-with-q

在类似 filter() 中,查询使用的关键字参数是通过 “AND” 连接起来的。如果你要执行更复杂的查询(例如,由 OR 语句连接的查询),你可以使用 Q 对象。

示例代码

Poll.objects.get(
    Q(question__startswith='Who'),
    Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6))
)

相当于SQL:

SELECT * from polls WHERE question LIKE 'Who%'
    AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')

通过 & 和 | 操作符和括号分组,组合任意复杂度的语句。当然, Q 对象也可通过 ~ 操作符反转,允许在组合查询中组合普通查询或反向 (NOT) 查询:

Poll.objects.get(
    Q(question__startswith='Who') | ~Q(pub_date__year=2005)
)