查询 API

本文档介绍如何使用 QuerySet 构建查询

务必查看 示例 以便更好地理解

从模型类开始查询

Event.filter(id=1)

模型本身有几种方法可以开始查询

  • filter(*args, **kwargs) - 使用给定的过滤器创建 QuerySet

  • exclude(*args, **kwargs) - 使用给定的排除过滤器创建 QuerySet

  • all() - 创建不带过滤器的 QuerySet

  • first() - 创建仅限于一个对象的 QuerySet,并返回实例而不是列表

  • annotate() - 创建具有给定注释的 QuerySet

此方法返回 QuerySet 对象,它允许进一步筛选和一些更复杂的操作

模型类也有这些方法来创建对象

  • create(**kwargs) - 使用给定的 kwargs 创建对象

  • get_or_create(defaults, **kwargs) - 获取给定 kwargs 的对象,如果找不到,则使用 defaults 字典中的附加 kwargs 创建它

模型本身的实例也有这些方法

  • save() - 更新实例,或插入实例(如果之前从未保存过)

  • delete() - 从数据库中删除实例

  • fetch_related(*args) - 获取与实例相关的对象。它可以获取 FK 关系、反向 FK 关系和 M2M 关系。它还可以获取相关对象的变量深度,如下所示:await team.fetch_related('events__tournament') - 这将获取团队的所有事件,并且对于这些事件中的每一个事件,它们的锦标赛也将被预先获取。获取对象后,它们应该可以正常使用,如下所示:team.events[0].tournament.name

在实例上处理相关对象的另一种方法是在 async for 中明确查询它们

async for team in event.participants:
    print(team.name)

您还可以像这样筛选相关对象

await team.events.filter(name='First')

它将返回一个具有预定义筛选条件的 QuerySet 对象

QuerySet

从对象获取查询集后,您可以对其执行以下操作

class tortoise.queryset.QuerySetSingle(*args, **kwargs)[source]

等待它将解析 Model 对象的单个实例,而不是序列。

class tortoise.queryset.QuerySet(model)[source]
__getitem__(key)[source]

Queryset 的查询偏移量和限制。

引发:
  • ParamsError – QuerySet 索引必须是切片。

  • ParamsError – 切片步长应为 1 或 None。

  • ParamsError – 切片开始应为非负数或 None。

  • ParamsError – 切片结束应为大于切片开始的非负数,

或 None。

返回类型:

QuerySet[Model]

all()[source]

返回整个 QuerySet。除了作为唯一操作之外,本质上是无操作。

返回类型:

QuerySet[Model]

annotate(**kwargs)[source]

使用聚合或函数结果对结果进行注释。

引发:

TypeError – 预计关键字参数的值为 Function 实例。

返回类型:

QuerySet[Model]

as_query()

返回实际查询。

返回类型:

QueryBuilder

bulk_create(objects, batch_size=None, ignore_conflicts=False, update_fields=None, on_conflict=None)[source]

此方法以高效的方式将提供的对象列表插入到数据库中(通常仅 1 个查询,无论有多少对象)。

参数:
on_conflict=None

冲突索引名称

update_fields=None

冲突时更新字段

ignore_conflicts=False

插入时忽略冲突

objects

要批量创建的对象列表

batch_size=None

在单个查询中创建的对象数量

引发:

ValueError – 如果参数不符合规范

返回类型:

BulkCreateQuery[Model]

bulk_update(objects, fields, batch_size=None)[source]

更新数据库中每个给定对象中给定的字段。

参数:
objects

要批量创建的对象列表

fields

要更新的字段

batch_size=None

在单个查询中创建的对象数量

引发:

ValueError – 如果对象没有设置主键

返回类型:

BulkUpdateQuery[Model]

count()[source]

返回查询集中对象的计数,而不是对象。

返回类型:

CountQuery

delete()[源代码]

删除 QuerySet 中的所有对象。

返回类型:

DeleteQuery

distinct()[源代码]

使 QuerySet 不同。

仅当与 .values().values_list() 结合使用时才有意义,因为它在所有获取的字段之前加上一个 distinct。

返回类型:

QuerySet[Model]

exclude(*args, **kwargs)[源代码]

与 .filter() 相同,但会将所有参数追加到 NOT

返回类型:

QuerySet[Model]

exists()[源代码]

返回 queryset 是否存在的 True/False。

返回类型:

ExistsQuery

async explain()[源代码]

获取并返回有关查询执行计划的信息。

这是通过执行 EXPLAIN 查询来完成的,其确切前缀取决于数据库后端,如下所述。

  • PostgreSQL: EXPLAIN (FORMAT JSON, VERBOSE) ...

  • SQLite: EXPLAIN QUERY PLAN ...

  • MySQL: EXPLAIN FORMAT=JSON ...

注意

这仅用于交互环境中进行调试和查询优化。输出格式可能会(并且将)根据数据库后端而有很大差异。

返回类型:

任意

filter(*args, **kwargs)[source]

按给定的 kwargs 过滤 QuerySet。您可以像这样按相关对象进行过滤

Team.filter(events__tournament__name='Test')

您还可以将 Q 对象作为 args 传递给过滤器。

返回类型:

QuerySet[Model]

first()[source]

将查询集限制为一个对象,并返回一个对象,而不是列表。

返回类型:

QuerySetSingle[Optional[Model]]

force_index(*index_names)[source]

FORCE INDEX 提示的作用类似于 USE INDEX (index_list),此外还假定表扫描非常昂贵。

返回类型:

QuerySet[Model]

get(*args, **kwargs)[source]

获取与参数匹配的单个对象。

返回类型:

QuerySetSingle[Model]

get_or_none(*args, **kwargs)[source]

获取与参数匹配的单个对象。

返回类型:

QuerySetSingle[Optional[Model]]

group_by(*fields)[source]

使 QuerySet 返回按组分组的字典或元组列表。

必须在 .values() 或 .values_list() 之前调用

返回类型:

QuerySet[Model]

async in_bulk(id_list, field_name)[source]

返回一个字典,将每个给定的 ID 映射到具有该 ID 的对象。如果未提供 id_list,则评估整个 QuerySet。

参数:
id_list

字段值列表

field_name

必须是唯一字段

返回类型:

Dict[str, Model]

limit(limit)[source]

将 QuerySet 限制为给定长度。

引发:

ParamsError – 限制应为非负数。

返回类型:

QuerySet[Model]

offset(offset)[source]

QuerySet 的查询偏移量。

引发:

ParamsError – 偏移量应为非负数。

返回类型:

QuerySet[Model]

only(*fields_for_select)[source]

仅获取指定字段以创建部分模型。

仅在以下情况下允许持久化模型上的更改

  • 要在 <model>.save(update_fields=[...]) 中更新的所有字段都已指定

  • 已在 .only(…)` 中包含模型主键

为了防止常见错误,我们确保引发错误

  • 如果访问未指定的字段,将收到 AttributeError

  • 如果执行 <model>.save(),将引发 IncompleteInstanceError,因为模型按请求不完整。

  • 如果执行 <model>.save(update_fields=[...]) 且未在 .only(...) 中包含主键,则将引发 IncompleteInstanceError,表明在不知道主键的情况下无法进行更新。

  • 如果执行 <model>.save(update_fields=[...])update_fields 中的一个字段不在 .only(...) 中,则将引发 IncompleteInstanceError,因为该字段不可用于更新。

返回类型:

QuerySet[Model]

order_by(*orderings)[source]

接受参数以按类似于以下格式进行筛选

.order_by('name', '-tournament__name')

还支持按相关模型排序。名称前面的“ - ”将导致降序排序,默认情况下为升序。

引发:

FieldError – 如果提供了未知字段。

返回类型:

QuerySet[Model]

类似于实例上的 .fetch_related(),但适用于 QuerySet 中的所有对象。

FieldError – 如果要预取的字段不是关系,或未找到。

QuerySet[Model]

raw(sql)[source]

从原始 SQL 返回 QuerySet

返回类型:

RawSQLQuery

resolve_filters(model, q_objects, annotations, custom_filters)

为 QuerySet 构建通用筛选器。

参数:
model

此查询集基于的模型。

q_objects

要应用的 Q 表达式。

annotations

要添加的额外注释。

custom_filters

要传递的预解析的筛选器。

返回类型:

resolve_ordering(model, table, orderings, annotations)

将标准排序应用到 QuerySet。

参数:
model

此查询集基于的模型。

table

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

orderings

要按哪些列/顺序排序

annotations

可以排序的注释

引发:

FieldError – 如果提供的字段在模型中不存在。

返回类型:

select_for_update(nowait=False, skip_locked=False, of=())[source]

使 QuerySet 选择更新。

返回一个查询集,它将锁定行直到事务结束,在支持的数据库上生成一个 SELECT … FOR UPDATE SQL 语句。

返回类型:

QuerySet[Model]

返回一个新的 QuerySet 实例,它将选择相关的对象。

如果指定了字段,它们必须是 ForeignKey 字段,并且只有那些相关对象包含在选择中。

QuerySet[Model]

sql(**kwargs)

返回实际的 SQL。

返回类型:

str

update(**kwargs)[source]

使用给定的 kwargs 更新 QuerySet 中的所有对象。

将更新数据库本身中的数据,而不是返回结果集。

返回类型:

UpdateQuery

use_index(*index_names)[source]

USE INDEX (index_list) 提示告诉 MySQL 仅使用命名的索引之一来查找表中的行。

返回类型:

QuerySet[Model]

using_db(_db)[source]

在提供的数据库客户端中执行查询。对事务解决方法很有用。

返回类型:

QuerySet[Model]

values(*args, **kwargs)[source]

使 QuerySet 返回字典而不是对象。

如果在 .get().get_or_none().first() 之后调用,则返回字典而不是对象。

可以传递要获取的字段的名称,或作为 field_name='name_in_dict' kwarg。

如果没有传递任何参数,则它将默认为包含所有字段的字典。

引发:

FieldError – 如果提供了重复键。

返回类型:

ValuesQuery[typing_extensions.Literal[False]]

values_list(*fields_, flat=False)[source]

使 QuerySet 返回给定参数的元组列表而不是对象。

如果在 .get().get_or_none().first() 之后调用,则返回给定参数的元组而不是对象。

如果 `flat=True 并且只传递了一个参数,则可以返回扁平列表或标量。

如果没有传递任何参数,则它将默认为包含按声明顺序排列的所有字段的元组。

返回类型:

ValuesListQuery[typing_extensions.Literal[False]]

tortoise.queryset.BulkCreateQuery(model, db, objects, batch_size=None, ignore_conflicts=False, update_fields=None, on_conflict=None)[源代码]
sql(**kwargs)[源代码]

返回实际的 SQL。

返回类型:

str

tortoise.queryset.BulkUpdateQuery(model, db, q_objects, annotations, custom_filters, limit, orderings, objects, fields, batch_size=None)[源代码]
sql(**kwargs)[源代码]

返回实际的 SQL。

返回类型:

str

tortoise.queryset.CountQuery(model, db, q_objects, annotations, custom_filters, limit, offset, force_indexes, use_indexes)[源代码]
tortoise.queryset.DeleteQuery(model, db, q_objects, annotations, custom_filters, limit, orderings)[源代码]
tortoise.queryset.ExistsQuery(model, db, q_objects, annotations, custom_filters, force_indexes, use_indexes)[源代码]
tortoise.queryset.FieldSelectQuery(model, annotations)[源代码]
tortoise.queryset.RawSQLQuery(model, db, sql)[源代码]
tortoise.queryset.UpdateQuery(model, update_kwargs, db, q_objects, annotations, custom_filters, limit, orderings)[源代码]
tortoise.queryset.ValuesListQuery(model, db, q_objects, single, raise_does_not_exist, fields_for_select_list, limit, offset, distinct, orderings, flat, annotations, custom_filters, group_bys, force_indexes, use_indexes)[源代码]
tortoise.queryset.ValuesQuery(model, db, q_objects, single, raise_does_not_exist, fields_for_select, limit, offset, distinct, orderings, annotations, custom_filters, group_bys, force_indexes, use_indexes)[源代码]

可以在不实际访问数据库的情况下构建、筛选和传递 QuerySet。仅在 await QuerySet 之后,它才会生成查询并针对数据库运行它。

以下是 QuerySet 的一些常见用法场景(我们使用 入门 中定义的模型)

常规选择进入模型实例

await Event.filter(name__startswith='FIFA')

此查询将获取所有以 FIFA 开头的 name 的事件,其中 name 是模型上定义的字段,而 startswith 是筛选修饰符。请注意,修饰符应由双下划线分隔。您可以在本文档的 筛选 部分中阅读有关筛选修饰符的更多信息。

还可以使用 .exclude() 筛选您的查询

await Team.exclude(name__icontains='junior')

当您使用相关数据时,一个更有趣的案例是,您还可以围绕相关实体构建查询

# getting all events, which tournament name is "World Cup"
await Event.filter(tournament__name='World Cup')

# Gets all teams participating in events with ids 1, 2, 3
await Team.filter(events__id__in=[1,2,3])

# Gets all tournaments where teams with "junior" in their name are participating
await Tournament.filter(event__participants__name__icontains='junior').distinct()

通常,您不仅希望按相关数据筛选,还希望获取相关数据。您可以使用 .prefetch_related() 来实现此目的

# This will fetch events, and for each of events ``.tournament`` field will be populated with
# corresponding ``Tournament`` instance
await Event.all().prefetch_related('tournament')

# This will fetch tournament with their events and teams for each event
tournament_list = await Tournament.all().prefetch_related('events__participants')

# Fetched result for m2m and backward fk relations are stored in list-like container
for tournament in tournament_list:
    print([e.name for e in tournament.events])

有关 prefetch_related() 工作原理的一般规则是,相关模型的每一层深度都会产生 1 个附加查询,因此 .prefetch_related('events__participants') 将产生两个附加查询来获取您的数据。

有时,当性能至关重要时,您不想进行这样的其他查询。在这种情况下,您可以使用 values()values_list() 来生成更有效的查询

# This will return list of dicts with keys 'id', 'name', 'tournament_name' and
# 'tournament_name' will be populated by name of related tournament.
# And it will be done in one query
events = await Event.filter(id__in=[1,2,3]).values('id', 'name', tournament_name='tournament__name')

QuerySet 还通过 .annotate() 方法支持聚合和数据库函数

from tortoise.functions import Count, Trim, Lower, Upper, Coalesce

# This query will fetch all tournaments with 10 or more events, and will
# populate filed `.events_count` on instances with corresponding value
await Tournament.annotate(events_count=Count('events')).filter(events_count__gte=10)
await Tournament.annotate(clean_name=Trim('name')).filter(clean_name='tournament')
await Tournament.annotate(name_upper=Upper('name')).filter(name_upper='TOURNAMENT')
await Tournament.annotate(name_lower=Lower('name')).filter(name_lower='tournament')
await Tournament.annotate(desc_clean=Coalesce('desc', '')).filter(desc_clean='')

查看 示例 以了解其所有功能

外键

Tortoise ORM 提供了一个用于处理 FK 关系的 API

class tortoise.fields.relational.ReverseRelation(remote_model, relation_field, instance, from_field)[source]

ForeignKeyField() 的关系容器。

all()[source]

返回包含所有相关元素的 QuerySet。

返回类型:

QuerySet[MODEL]

filter(*args, **kwargs)[source]

返回按 args/kwargs 过滤的相关元素的 QuerySet。

返回类型:

QuerySet[MODEL]

limit(limit)[source]

返回最多包含 «limit» 个相关元素的 QuerySet。

返回类型:

QuerySet[MODEL]

offset(offset)[source]

返回一个 QuerySet,其中所有相关元素都偏移了 «offset»。

返回类型:

QuerySet[MODEL]

order_by(*orderings)[source]

按顺序返回一个 QuerySet 相关元素。

返回类型:

QuerySet[MODEL]

tortoise.fields.relational.ForeignKeyNullableRelation

在获取的模型可能为 null 时,访问模型中 ForeignKeyField() 字段的结果的类型提示。

Optional[ForeignKeyFieldInstance[MODEL]]] 的别名

tortoise.fields.relational.ForeignKeyRelation

访问模型中 ForeignKeyField() 字段的结果的类型提示。

ForeignKeyFieldInstance[MODEL]] 的别名

一对一

tortoise.fields.relational.OneToOneNullableRelation

在获取的模型可能为 null 时,访问模型中 OneToOneField() 字段的结果的类型提示。

Optional[OneToOneFieldInstance[MODEL]]] 的别名

tortoise.fields.relational.OneToOneRelation

访问模型中的 OneToOneField() 字段的结果的类型提示。

OneToOneFieldInstance[MODEL] 的别名

多对多

Tortoise ORM 提供了一个用于处理 M2M 关系的 API

class tortoise.fields.relational.ManyToManyRelation(instance, m2m_field)[source]

ManyToManyField() 的多对多关系容器。

async add(*instances, using_db=None)[source]

将一个或多个 instances 添加到关系中。

如果已经添加,则会静默忽略。

引发:

OperationalError – 如果要添加的对象未保存。

返回类型:

all()

返回包含所有相关元素的 QuerySet。

返回类型:

QuerySet[MODEL]

async clear(using_db=None)[source]

清除所有关系。

返回类型:

filter(*args, **kwargs)

返回按 args/kwargs 过滤的相关元素的 QuerySet。

返回类型:

QuerySet[MODEL]

limit(limit)

返回最多包含 «limit» 个相关元素的 QuerySet。

返回类型:

QuerySet[MODEL]

offset(offset)

返回一个 QuerySet,其中所有相关元素都偏移了 «offset»。

返回类型:

QuerySet[MODEL]

order_by(*orderings)

按顺序返回一个 QuerySet 相关元素。

返回类型:

QuerySet[MODEL]

async remove(*instances, using_db=None)[source]

从关系中删除一个或多个instances

引发:

OperationalError – remove() 被调用时没有实例。

返回类型:

您可以像这样使用它们

await event.participants.add(participant_1, participant_2)

过滤

当使用.filter()方法时,您可以使用字段名称的多个修饰符来指定所需的操作

teams = await Team.filter(name__icontains='CON')
  • not

  • in - 检查字段值是否在传入的列表中

  • not_in

  • gte - 大于或等于传入的值

  • gt - 大于传入的值

  • lte - 小于或等于传入的值

  • lt - 小于传入的值

  • range - 在给定的两个值之间

  • isnull - 字段为 null

  • not_isnull - 字段不为 null

  • contains - 字段包含指定的子字符串

  • icontains - 不区分大小写的 contains

  • startswith - 如果字段以值开头

  • istartswith - 不区分大小写的 startswith

  • endswith - 如果字段以值结尾

  • iendswith - 不区分大小写的 endswith

  • iexact - 不区分大小写的等于

  • search - 全文搜索

特别是,你可以使用以下选项之一来过滤日期部分,请注意当前仅支持 PostgreSQL 和 MySQL,但不支持 sqlite

class DatePart(Enum):
    year = "YEAR"
    quarter = "QUARTER"
    month = "MONTH"
    week = "WEEK"
    day = "DAY"
    hour = "HOUR"
    minute = "MINUTE"
    second = "SECOND"
    microsecond = "MICROSECOND"

teams = await Team.filter(created_at__year=2020)
teams = await Team.filter(created_at__month=12)
teams = await Team.filter(created_at__day=5)

在 PostgreSQL 和 MYSQL 中,你可以在 JSONField 中使用 containscontained_byfilter 选项

class JSONModel:
    data = fields.JSONField()

await JSONModel.create(data=["text", 3, {"msg": "msg2"}])
obj = await JSONModel.filter(data__contains=[{"msg": "msg2"}]).first()

await JSONModel.create(data=["text"])
await JSONModel.create(data=["tortoise", "msg"])
await JSONModel.create(data=["tortoise"])

objects = await JSONModel.filter(data__contained_by=["text", "tortoise", "msg"])
class JSONModel:
    data = fields.JSONField()

await JSONModel.create(data={"breed": "labrador",
                             "owner": {
                                 "name": "Boby",
                                 "last": None,
                                 "other_pets": [
                                     {
                                         "name": "Fishy",
                                     }
                                 ],
                             },
                         })

obj1 = await JSONModel.filter(data__filter={"breed": "labrador"}).first()
obj2 = await JSONModel.filter(data__filter={"owner__name": "Boby"}).first()
obj3 = await JSONModel.filter(data__filter={"owner__other_pets__0__name": "Fishy"}).first()
obj4 = await JSONModel.filter(data__filter={"breed__not": "a"}).first()
obj5 = await JSONModel.filter(data__filter={"owner__name__isnull": True}).first()
obj6 = await JSONModel.filter(data__filter={"owner__last__not_isnull": False}).first()

复杂预取

有时需要仅获取某些相关的记录。你可以使用 Prefetch 对象来实现

tournament_with_filtered = await Tournament.all().prefetch_related(
    Prefetch('events', queryset=Event.filter(name='First'))
).first()

你可以在这里查看完整示例:预取

class tortoise.query_utils.Prefetch(relation, queryset, to_attr=None)[source]

预取容器。当想要附加一个自定义 QuerySet 以进行专门预取时,直接使用此容器。

参数:
relation : str

相关字段名称。

queryset : 'QuerySet'

用于预取的自定义 QuerySet。

to_attr : Optional[str]

将预取操作的结果设置为自定义属性。

resolve_for_queryset(queryset)[source]

在内部调用以生成预取查询。

参数:
queryset : 'QuerySet'

用于预取的自定义 QuerySet。

引发:

OperationalError – 如果字段在模型中不存在。

返回类型: