Q查询和F查询
Q查询
在filter() 等方法中,查询使用的关键字参数是通过 “SQL AND” 连接起来的。如果你要执行更复杂的查询(例如,由 SQL OR 语句连接的查询),可以使用 Q 对象。 一个 Q 对象 (django.db.models.Q) 用于压缩关键字参数集合。
Q 对象能通过 & 和 | 操作符连接起来。当操作符被用于两个 Q 对象之间时会生成一个新的 Q 对象。例如:
Q(question__startswith='Who') | Q(question__startswith='What')
等价于如下SQL语句:
WHERE question LIKE 'Who%' OR question LIKE 'What%'
每个接受关键字参数的查询函数 (例如 filter(), exclude(), get()) 也同时接受一个或多个 Q 对象作为位置(未命名的)参数。若你为查询函数提供了多个 Q 对象参数,这些参数会通过 “AND” 连接。例如:
Poll.objects.get(Q(question__startswith='Who'),Q(pub_date=date(2005, 5, 2)) | (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 对象和关键字参数。所有提供给查询函数的参数(即关键字参数或 Q 对象)均通过 “AND” 连接。然而,若提供了 Q 对象,那么它必须位于所有关键字参数之前。例如:
Poll.objects.get(Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(20055, 6)),question__startswith='Who',)
Q对象还可以完成NOT操作,例如:
BookInfo.objects.filter(~Q(id=3))
大概等价于SQL语句:
SELECT * FROM bookinfo WHERE id !=3
F查询
Django 使用 F() 对象来生成一个 SQL 表达式,直接在数据库层面进行操作。例如:
代码语言:javascript复制from django.db.models import F
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') 1
reporter.save()
虽然 reporter.stories_filed = F(‘stories_filed’) 1 看起来像一个普通的 Python 赋值给一个实例属性,但实际上它是一个描述数据库操作的 SQL 结构。
当 Django 遇到 F() 的实例时,它会覆盖标准的 Python 运算符来创建一个封装的 SQL 表达式;在本例中,它指示数据库递增由 reporter.stories_filed 表示的数据库字段。
无论 reporter.stories_filed 上的值是多少,Python 永远不会知道它——它完全由数据库处理。通过 Django 的 F() 类,Python 所做的就是创建 SQL 语法来引用这个字段并描述操作。
F() 除了用于上述对单个实例的操作外,F() 还可以与 update() 一起用于对象实例的 QuerySets。这就把我们上面使用的两个查询——get() 和 save() 减少到只有一个:
代码语言:javascript复制reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') 1)
因此,F() 可以通过以下方式提供性能优势:
- 让数据库,而不是 Python 来完成工作;
- 减少某些操作所需的查询次数。
避免竞争
F() 的另一个有用的好处是,让数据库——而不是 Python——更新一个字段的值,避免了 竞争条件。
如果两个 Python 线程执行上面第一个例子中的代码,一个线程可以在另一个线程从数据库中获取一个字段的值后,检索、递增并保存它。第二个线程保存的值将基于原始值,第一个线程的工作将丢失。
如果数据库负责更新字段,那么这个过程就比较稳健:它只会在执行 save() 或 update() 时,根据数据库中字段的值来更新字段,而不是根据检索实例时的值来更新。
注意:F() 赋值在 Model.save() 之后持续存在
F() 分配给模型字段的对象在保存模型实例后会持续存在,并将应用于每个 save()。例如:
代码语言:javascript复制reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') 1
reporter.save()
reporter.name = 'Tintin Jr.'
reporter.save()
在这种情况下,stories_filed 将被更新两次。如果最初是 1,最终值将是 3。这种持久性可以通过在保存模型对象后重新加载来避免,例如,可以重新进行查询,获取该对象。
根据字段的值来进行查询
F() 在 QuerySet 过滤器中也非常有用,它们可以根据对象的字段值而不是 Python 值的标准来过滤一组对象。F()能将模型字段值与同一模型中的另一字段做比较。例如:
代码语言:javascript复制from django.db.models import F
Entry.objects.filter(number_of_comments__gt=F('number_of_pingbacks'))
查出所有评论数大于 pingbacks 的博客条目。