表达式¶
Q 表达式¶
有时,你需要执行比简单的 AND <model>.filter()
提供的更复杂的查询。幸运的是,我们有 Q 对象来丰富内容并帮助你找到所需内容。然后,这些 Q 对象可以用作 <model>.filter()
的参数。
- Q 对象非常通用,一些示例用例
创建 OR 过滤器
嵌套过滤器
反向过滤器
组合上述任何一种,轻松编写复杂的多层过滤器
Q 对象可以采用任何(特殊)关键字参数进行过滤,<model>.filter()
接受这些参数,请参阅这些文档,了解有关该方面的完整过滤器选项列表。
它们还可以通过使用按位运算符(|
是 OR,&
是 AND,对于不熟悉按位运算符的人来说)进行组合
例如,要找到名称为 Event 1
或 Event 2
的事件
found_events = await Event.filter(
Q(name='Event 1') | Q(name='Event 2')
)
Q 对象也可以嵌套,例如上述等同于
found_events = await Event.filter(
Q(Q(name='Event 1'), Q(name='Event 2'), join_type="OR")
)
如果省略连接类型,则默认为 AND
。
注意
没有过滤器参数的 Q 对象被视为 NOP,并且在最终查询中将被忽略(无论它们用作 AND
还是 OR
参数)
此外,Q 对象支持否定以在查询中生成 NOT
(~
运算符)子句
not_third_events = await Event.filter(~Q(name='3'))
-
class tortoise.expressions.Q(*args, join_type=
'AND'
, **kwargs)[source]¶ Q 表达式容器。Q 表达式是一个有用的工具,可以从许多小部分中组合查询。
-
AND =
'AND'
¶
-
OR =
'OR'
¶
- __and__(other)[source]¶
返回 Q 对象的二进制 AND,使用
AND
运算符。- 引发:¶
OperationalError – AND 操作需要一个 Q 节点
- 返回类型:¶
- filters : dict[str, FilterInfoDict]¶
包含应用于此 Q 的过滤器
- join_type¶
指定此 Q 对其子项执行 AND 或 OR
-
AND =
F 表达式¶
F 对象表示模型字段的值。它可以引用模型字段值并在不实际将它们从数据库提取到 Python 内存的情况下使用它们执行数据库操作。
例如,使用 F
更新用户余额原子
from tortoise.expressions import F
await User.filter(id=1).update(balance = F('balance') - 10)
await User.filter(id=1).update(balance = F('balance') + F('award'), award = 0)
# or use .save()
user = await User.get(id=1)
user.balance = F('balance') - 10
await user.save(update_fields=['balance'])
为此,如果你想再次访问更新的 F 字段,则应首先调用 refresh_from_db 来刷新特殊字段。
# Can't do this!
balance = user.balance
await user.refresh_from_db(fields=['balance'])
# Great!
balance = user.balance
你还可以使用 F 中的 annotate。
data = await User.annotate(idp=F("id") + 1).values_list("id", "idp")
子查询¶
你可以在 filter() 和 annotate() 中使用 Subquery。
from tortoise.expressions import Subquery
await Tournament.annotate(ids=Subquery(Tournament.all().limit(1).values("id"))).values("ids", "id")
await Tournament.filter(pk=Subquery(Tournament.filter(pk=t1.pk).values("id"))).first()
RawSQL¶
RawSQL 就像 Subquery,但提供了编写原始 sql 的能力。
你可以在 filter() 和 annotate() 中使用 RawSQL。
await Tournament.filter(pk=1).annotate(count=RawSQL('count(*)')).values("count")
await Tournament.filter(pk=1).annotate(idp=RawSQL('id + 1')).filter(idp=2).values("idp")
await Tournament.filter(pk=RawSQL("id + 1"))
Case-When 表达式¶
构建经典 CASE WHEN … THEN … ELSE … END sql 片段。
results = await IntModel.all().annotate(category=Case(When(intnum__gte=8, then='big'), When(intnum__lte=2, then='small'), default='middle'))