F 对象:让“阅读量>评论量”这种需求 1 行代码就能搞定 Q 对象:让 “并且、或者、非” 三种逻辑在 ORM 里一行搞定

举报
周杰伦本人 发表于 2025/08/31 20:18:34 2025/08/31
【摘要】 F 对象:让“阅读量>评论量”这种需求 1 行代码就能搞定 Q 对象:让 “并且、或者、非” 三种逻辑在 ORM 里一行搞定 场景:运营同学提需求“把阅读量 大于 评论量的书找出来,再顺便把阅读量 大于评论量两倍 的也列出来。” 传统 SQL 写法-- 阅读量 > 评论量SELECT * FROM bookinfo WHERE read_count > comment_cnt;-- 阅读量...

F 对象:让“阅读量>评论量”这种需求 1 行代码就能搞定 Q 对象:让 “并且、或者、非” 三种逻辑在 ORM 里一行搞定

场景:运营同学提需求

“把阅读量 大于 评论量的书找出来,再顺便把阅读量 大于评论量两倍 的也列出来。”


传统 SQL 写法

-- 阅读量 > 评论量
SELECT * FROM bookinfo WHERE read_count > comment_cnt;

-- 阅读量 > 评论量 * 2
SELECT * FROM bookinfo WHERE read_count > comment_cnt * 2;

要写两条 SQL,还得自己算乘法。


Django ORM 写法:F 对象一行搞定

1. 引入 F

from django.db.models import F

2. 阅读量 > 评论量

BookInfo.objects.filter(read_count__gt=F('comment_cnt'))
# 返回 <QuerySet [<BookInfo: 雪山飞狐>]>

3. 阅读量 > 评论量 * 2

BookInfo.objects.filter(read_count__gt=F('comment_cnt') * 2)

F('comment_cnt') * 2 直接在 SQL 层完成乘法,不先拉数据到内存


一句话记忆

  • F(‘字段名’) 代表数据库列本身

  • 支持运算+ - * / %

  • 无需 save,直接生成 SQL 条件

Q 对象:让 “并且、或者、非” 三种逻辑在 ORM 里一行搞定


场景引入

运营同学提了两个需求:

  1. 并且:把“阅读量大于 20 编号 < 3” 的书找出来。

  2. 或者:把“阅读量大于 20 编号 < 3” 的书找出来。

用原生 SQL 要写两段 WHERE … AND …WHERE … OR …,Django 里却只要 Q 对象 一行完成。


1️⃣ 并且查询(AND)

写法 ①:链式 filter(最简单)

BookInfo.objects.filter(
    read_count__gt=20,
    id__lt=3
)

写法 ②:Q 对象显式 AND

from django.db.models import Q

BookInfo.objects.filter(
    Q(read_count__gt=20) & Q(id__lt=3)
)
结果 解释
只返回 同时满足 两个条件的记录 & 就是 SQL 里的 AND

2️⃣ 或者查询(OR)

BookInfo.objects.filter(
    Q(read_count__gt=20) | Q(id__lt=3)
)
结果 解释
只要满足 任意一个 条件即可返回 `

3️⃣ 非查询(NOT)

把“编号 不等于 3” 的书排除掉:

# 写法 ①:exclude
BookInfo.objects.exclude(id=3)

# 写法 ②:Q 对象取反
BookInfo.objects.filter(~Q(id=3))
符号 含义
~ 逻辑 NOT,相当于 SQL 里的 NOT

4️⃣ 混合逻辑:括号优先级

再升级需求:

“阅读量>20 (编号<3 书名含‘剑’)”

BookInfo.objects.filter(
    Q(read_count__gt=20) &
    (Q(id__lt=3) | Q(name__contains='剑'))
)

Q 对象天然支持 括号级联,SQL 自动生成 () 保证优先级。


记忆口诀

  • 并且 &

  • 或者 \|

  • ~

  • 双下划线 + 运算符 永远不变


30 秒小练习

把下面空格补齐:

from django.db.models import Q
# 阅读量>50 或 编号<=2,但排除书名含“飞”的书
BookInfo.objects.filter(
    Q(read_count__gt=50) | Q(id__lte=2)
).exclude(name__contains='飞')

答案已在代码里,直接复制即可跑通!

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。