前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Q查询和F查询

Q查询和F查询

作者头像
zy010101
发布2021-10-20 17:00:22
1.4K0
发布2021-10-20 17:00:22
举报
文章被收录于专栏:程序员

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() 可以通过以下方式提供性能优势:

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

避免竞争

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 的博客条目。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2021/10/15 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Q查询和F查询
    • Q查询
      • F查询
        • 避免竞争
        • 根据字段的值来进行查询
    相关产品与服务
    数据库
    云数据库为企业提供了完善的关系型数据库、非关系型数据库、分析型数据库和数据库生态工具。您可以通过产品选择和组合搭建,轻松实现高可靠、高可用性、高性能等数据库需求。云数据库服务也可大幅减少您的运维工作量,更专注于业务发展,让企业一站式享受数据上云及分布式架构的技术红利!
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档