查询集代理
当直接访问相关的ManyToMany字段以及ReverseForeignKey时,返回相关模型的列表。
但同时它公开了 QuerySet API 的子集,因此您可以直接从父模型过滤、创建、选择相关模型等。
!!!注意 默认情况下,公开的 QuerySet 已被过滤为仅返回与父模型相关的模型。
| So if you issue `post.categories.all()` you will get all categories related to that post, not all in table.
|
!!!note 请注意,通过 QuerysetProxy 访问 QuerySet API 方法时,您不需要像普通查询那样使用对象属性。
| So note that it's `post.categories.all()` and **not** `post.categories.objects.all()`.
To learn more about available QuerySet methods visit [queries][queries]
|
!!!警告从ManyToMany 查询相关模型会清除父模型上加载的相关模型列表:
| Example: `post.categories.first()` will set post.categories to list of 1 related model -> the one returned by first()
Example 2: if post has 4 categories so `len(post.categories) == 4` calling `post.categories.limit(2).all()`
-> will load only 2 children and now `assert len(post.categories) == 2`
This happens for all QuerysetProxy methods returning data: `get`, `all` and `first` and in `get_or_create` if model already exists.
Note that value returned by `create` or created in `get_or_create` and `update_or_create`
if model does not exist will be added to relation list (not clearing it).
|
从数据库读取数据
得到
get(**kwargs): -> 模型
要仅获取按名称过滤的相关模型之一,您可以使用 get(**kwargs) 方法。
| # grab one category
assert news == await post.categories.get(name="News")
# note that method returns the category so you can grab this value
# but it also modifies list of related models in place
# so regardless of what was previously loaded on parent model
# now it has only one value -> just loaded with get() call
assert len(post.categories) == 1
assert post.categories[0] == news
|
获取或创建
get_or_create(_defaults: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[Model, bool]
尝试获取满足条件的行,如果引发 NoMatch 异常,则会使用给定的 kwargs 和 _defaults 创建一个新行。
!!!tip 在查询文档 get_or_create 中阅读更多内容
全部
all(**kwargs) -> List[Optional["Model"]]
要获取相关模型的列表,请使用 all() 方法。
请注意,您可以像普通查询一样过滤查询集、选择相关、排除字段等。
| # with all Queryset methods - filtering, selecting columns, counting etc.
await news.posts.filter(title__contains="M2M").all()
await Category.objects.filter(posts__author=guido).get()
# columns models of many to many relation can be prefetched
news_posts = await news.posts.select_related("author").all()
assert news_posts[0].author == guido
|
迭代
iterate(**kwargs) -> AsyncGenerator["Model"]
要迭代相关模型,请使用 iterate() 方法。
请注意,您可以像普通查询一样过滤查询集、选择相关、排除字段等。
| # iterate on categories of this post with an async generator
async for category in post.categories.iterate():
print(category.name)
|
向数据库插入/更新数据
创造
创建(**kwargs):-> 模型
直接从父模型创建相关模型。
链接表以及数据库中的关系 ID 会自动填充。
| # Creating columns object from instance:
await post.categories.create(name="Tips")
assert len(await post.categories.all()) == 2
# newly created instance already have relation persisted in the database
|
对于多对多关系,如果您在显式提供的直通模型上声明了其他字段,则有一个传递参数的附加功能,该功能将用于创建直通模型。
给定这样的样本:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | import databases
import ormar
import sqlalchemy
DATABASE_URL = "sqlite:///test.db"
ormar_base_config = ormar.OrmarConfig(
database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)
class Category(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="categories")
id = ormar.Integer(primary_key=True)
name = ormar.String(max_length=40)
class PostCategory(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="posts_x_categories")
id: int = ormar.Integer(primary_key=True)
sort_order: int = ormar.Integer(nullable=True)
param_name: str = ormar.String(default="Name", max_length=200)
class Post(ormar.Model):
ormar_config = ormar_base_config.copy()
id: int = ormar.Integer(primary_key=True)
title: str = ormar.String(max_length=200)
categories = ormar.ManyToMany(Category, through=PostCategory)
|
您可以通过以下方式在 create() 调用中通过模型填充字段:
| post = await Post(title="Test post").save()
await post.categories.create(
name="Test category1",
# in arguments pass a dictionary with name of the through field and keys
# corresponding to through model fields
postcategory={"sort_order": 1, "param_name": "volume"},
)
|
获取或创建
get_or_create(_defaults: Optional[Dict[str, Any]] = None, **kwargs) -> Tuple[Model, bool]
尝试获取满足条件的行,如果引发 NoMatch 异常,则会使用给定的 kwargs 创建一个新行。
!!!tip 在查询文档 get_or_create 中阅读更多内容
更新或创建
update_or_create(**kwargs) -> Model
更新模型,或者在数据库中没有匹配项的情况下创建一个新模型。
!!!tip 在查询文档 update_or_create 中阅读更多内容
更新
update(**kwargs, each:bool = False) -> int
使用提供的关键字参数更新相关模型,返回更新的行数。
请注意,对于多对多关系更新还可以接受带有字段名称和字段字典的参数。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 | import databases
import ormar
import sqlalchemy
DATABASE_URL = "sqlite:///test.db"
ormar_base_config = ormar.OrmarConfig(
database=databases.Database(DATABASE_URL), metadata=sqlalchemy.MetaData()
)
class Category(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="categories")
id = ormar.Integer(primary_key=True)
name = ormar.String(max_length=40)
class PostCategory(ormar.Model):
ormar_config = ormar_base_config.copy(tablename="posts_x_categories")
id: int = ormar.Integer(primary_key=True)
sort_order: int = ormar.Integer(nullable=True)
param_name: str = ormar.String(default="Name", max_length=200)
class Post(ormar.Model):
ormar_config = ormar_base_config.copy()
id: int = ormar.Integer(primary_key=True)
title: str = ormar.String(max_length=200)
categories = ormar.ManyToMany(Category, through=PostCategory)
|
在上面的示例中,您可以在以下调用中更新 postcategory 的属性:
| await post.categories.filter(name="Test category3").update(
postcategory={"sort_order": 4}
)
|
过滤和排序
筛选
filter(*args, **kwargs) -> QuerySet
允许您使用跨 FK 关系的过滤器按任何模型属性/字段进行过滤以及获取实例。
排除
exclude(*args, **kwargs) -> QuerySet
与过滤器的工作原理完全相同,并且所有修饰符(后缀)都相同,但返回 not 条件。
订单依据
order_by(columns:Union[List, str]) -> QuerySet
使用 order_by(),您可以根据您选择的字段对数据库中的结果进行排序。
!!!tip 在查询文档 order_by 中阅读更多内容
连接和子查询
选择相关
select_related(related: Union[List, str]) -> QuerySet
允许在同一查询期间预取相关模型。
使用 select_lated 时,始终只对数据库运行一个查询,这意味着会生成一个(有时很复杂)连接,并在 python 中处理稍后的嵌套模型。
!!!tip 在查询文档中阅读 select_lated 的更多内容
预取相关
prefetch_related(related: Union[List, str]) -> QuerySet
允许在查询期间预取相关模型 - 但与 select_lated 相反,每个后续模型都是在单独的数据库查询中获取的。
使用 prefetch_lated 时,每个模型都会针对数据库运行一个查询,这意味着您将一个接一个地执行多个查询。
!!!tip 在查询文档 prefetch_lated 中阅读更多内容
分页和行数
分页
paginate(page: int, page_size: int = 20) -> QuerySet
结合了基于页码和大小的偏移和限制方法。
限制
limit(limit_count: int) -> QuerySet
您可以将结果限制为所需的父模型数量。
抵消
offset(offset: int) -> QuerySet
您可以通过所需的主模型数量来抵消结果。
选择列的子集
领域
fields(columns: Union[List, str, set, dict]) -> QuerySet
使用 fields(),您可以选择模型列的子集来限制数据负载。
排除字段
exclude_fields(columns: Union[List, str, set, dict]) -> QuerySet
使用 except_fields(),您可以选择将排除的模型列的子集以限制数据加载。
!!!tip 在查询文档中了解更多信息 except_fields
聚合函数
数数
count(distinct: bool = True) -> int
返回与给定条件匹配的行数(即应用过滤器和排除)
存在
存在() -> 布尔值
返回一个布尔值以确认是否有符合给定条件的行(与过滤器和排除一起应用)