表达式

Q 表达式

有时,你需要执行比简单的 AND <model>.filter() 提供的更复杂的查询。幸运的是,我们有 Q 对象来丰富内容并帮助你找到所需内容。然后,这些 Q 对象可以用作 <model>.filter() 的参数。

Q 对象非常通用,一些示例用例
  • 创建 OR 过滤器

  • 嵌套过滤器

  • 反向过滤器

  • 组合上述任何一种,轻松编写复杂的多层过滤器

Q 对象可以采用任何(特殊)关键字参数进行过滤,<model>.filter() 接受这些参数,请参阅这些文档,了解有关该方面的完整过滤器选项列表。

它们还可以通过使用按位运算符(| 是 OR,& 是 AND,对于不熟悉按位运算符的人来说)进行组合

例如,要找到名称为 Event 1Event 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 表达式是一个有用的工具,可以从许多小部分中组合查询。

参数:
join_type='AND'

连接是 AND 还是 OR 连接类型?

*args

要包装的内部 Q 表达式。

**kwargs

此 Q 对象应封装的过滤器语句。

AND = 'AND'
OR = 'OR'
__and__(other)[source]

返回 Q 对象的二进制 AND,使用 AND 运算符。

引发:

OperationalError – AND 操作需要一个 Q 节点

返回类型:

Q

__invert__()[source]

返回 Q 对象的否定实例,使用 ~ 运算符。

返回类型:

Q

__or__(other)[source]

返回 Q 对象的二进制 OR,使用 OR 运算符。

引发:

OperationalError – OR 操作需要一个 Q 节点

返回类型:

Q

children : tuple[Q, ...]

包含构成此 Q 的子 Q

filters : dict[str, FilterInfoDict]

包含应用于此 Q 的过滤器

join_type

指定此 Q 对其子项执行 AND 或 OR

negate()[源代码]

否定当前 Q 对象。(突变)

返回类型:

resolve(model, table)[源代码]

将逻辑 Q 链解析为 SQL 语句的部分内容。

参数:
model

应在此 Q 表达式上解析的模型。

table

pypika.Table 用于跟踪虚拟 SQL 表(以允许自引用联接)

返回类型:

QueryModifier

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 片段。

tortoise.expressions.When(*args, then, negate=False, **kwargs)[源代码]

When 表达式。

参数:
*args

Q 对象

**kwargs

关键字准则(如筛选器)

then

准则值

negate=False

false(默认)

tortoise.expressions.Case(*args, default=None)[源代码]

Case 表达式。

参数:
*args

When 对象

default=None

‘CASE WHEN … THEN … ELSE <default> END’ 的值

results = await IntModel.all().annotate(category=Case(When(intnum__gte=8, then='big'), When(intnum__lte=2, then='small'), default='middle'))