查询 API¶
本文档介绍如何使用 QuerySet 构建查询
务必查看 示例 以便更好地理解
从模型类开始查询
Event.filter(id=1)
模型本身有几种方法可以开始查询
filter(*args, **kwargs)
- 使用给定的过滤器创建 QuerySetexclude(*args, **kwargs)
- 使用给定的排除过滤器创建 QuerySetall()
- 创建不带过滤器的 QuerySetfirst()
- 创建仅限于一个对象的 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.QuerySet(model)[source]¶
- __getitem__(key)[source]¶
Queryset 的查询偏移量和限制。
- 引发:¶
ParamsError – QuerySet 索引必须是切片。
ParamsError – 切片步长应为 1 或 None。
ParamsError – 切片开始应为非负数或 None。
ParamsError – 切片结束应为大于切片开始的非负数,
或 None。
-
bulk_create(objects, batch_size=
None
, ignore_conflicts=False
, update_fields=None
, on_conflict=None
)[source]¶ 此方法以高效的方式将提供的对象列表插入到数据库中(通常仅 1 个查询,无论有多少对象)。
-
bulk_update(objects, fields, batch_size=
None
)[source]¶ 更新数据库中每个给定对象中给定的字段。
- distinct()[源代码]¶
使 QuerySet 不同。
仅当与
.values()
或.values_list()
结合使用时才有意义,因为它在所有获取的字段之前加上一个 distinct。
- 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 传递给过滤器。
- first()[source]¶
将查询集限制为一个对象,并返回一个对象,而不是列表。
- 返回类型:¶
QuerySetSingle
[Optional
[Model]]
- get(*args, **kwargs)[source]¶
获取与参数匹配的单个对象。
- 返回类型:¶
QuerySetSingle
[Model]
- get_or_none(*args, **kwargs)[source]¶
获取与参数匹配的单个对象。
- 返回类型:¶
QuerySetSingle
[Optional
[Model]]
- async in_bulk(id_list, field_name)[source]¶
返回一个字典,将每个给定的 ID 映射到具有该 ID 的对象。如果未提供 id_list,则评估整个 QuerySet。
- 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
,因为该字段不可用于更新。
- order_by(*orderings)[source]¶
接受参数以按类似于以下格式进行筛选
.order_by('name', '-tournament__name')
还支持按相关模型排序。名称前面的“ - ”将导致降序排序,默认情况下为升序。
- 引发:¶
FieldError – 如果提供了未知字段。
- 返回类型:¶
QuerySet
[Model]
类似于实例上的
.fetch_related()
,但适用于 QuerySet 中的所有对象。FieldError – 如果要预取的字段不是关系,或未找到。
QuerySet
[Model]
- resolve_filters(model, q_objects, annotations, custom_filters)¶
为 QuerySet 构建通用筛选器。
- resolve_ordering(model, table, orderings, annotations)¶
将标准排序应用到 QuerySet。
-
select_for_update(nowait=
False
, skip_locked=False
, of=()
)[source]¶ 使 QuerySet 选择更新。
返回一个查询集,它将锁定行直到事务结束,在支持的数据库上生成一个 SELECT … FOR UPDATE SQL 语句。
返回一个新的 QuerySet 实例,它将选择相关的对象。
如果指定了字段,它们必须是 ForeignKey 字段,并且只有那些相关对象包含在选择中。
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
)[源代码]¶
-
类 tortoise.queryset.BulkUpdateQuery(model, db, q_objects, annotations, custom_filters, limit, orderings, objects, fields, batch_size=
None
)[源代码]¶
- 类 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.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()
的关系容器。
- 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 – 如果要添加的对象未保存。
- 返回类型:¶
无
-
async remove(*instances, using_db=
None
)[source]¶ 从关系中删除一个或多个
instances
。- 引发:¶
OperationalError – remove() 被调用时没有实例。
- 返回类型:¶
无
-
async add(*instances, using_db=
您可以像这样使用它们
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
- 字段为 nullnot_isnull
- 字段不为 nullcontains
- 字段包含指定的子字符串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
中使用 contains
、contained_by
和 filter
选项
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()
你可以在这里查看完整示例:预取