Skip to content

查询集代理

当直接访问相关的ManyToMany字段以及ReverseForeignKey时,返回相关模型的列表。

但同时它公开了 QuerySet API 的子集,因此您可以直接从父模型过滤、创建、选择相关模型等。

!!!注意 默认情况下,公开的 QuerySet 已被过滤为仅返回与父模型相关的模型。

1
So if you issue `post.categories.all()` you will get all categories related to that post, not all in table.

!!!note 请注意,通过 QuerysetProxy 访问 QuerySet API 方法时,您不需要像普通查询那样使用对象属性。

1
2
3
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 查询相关模型会清除父模型上加载的相关模型列表:

1
2
3
4
5
6
7
8
9
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) 方法。

1
2
3
4
5
6
7
8
9
# 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

Tip

获取或创建

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() 方法。

请注意,您可以像普通查询一样过滤查询集、选择相关、排除字段等。

1
2
3
4
5
6
7
# 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

Tip

迭代

iterate(**kwargs) -> AsyncGenerator["Model"]

要迭代相关模型,请使用 iterate() 方法。

请注意,您可以像普通查询一样过滤查询集、选择相关、排除字段等。

1
2
3
# iterate on categories of this post with an async generator
async for category in post.categories.iterate():
    print(category.name)

Tip

向数据库插入/更新数据

创造

创建(**kwargs):-> 模型

直接从父模型创建相关模型。

链接表以及数据库中的关系 ID 会自动填充。

1
2
3
4
# 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

Tip

对于多对多关系,如果您在显式提供的直通模型上声明了其他字段,则有一个传递参数的附加功能,该功能将用于创建直通模型。

给定这样的样本:

 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() 调用中通过模型填充字段:

1
2
3
4
5
6
7
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

使用提供的关键字参数更新相关模型,返回更新的行数。

Tip

请注意,对于多对多关系更新还可以接受带有字段名称和字段字典的参数。

 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 的属性:

1
2
3
await post.categories.filter(name="Test category3").update(
            postcategory={"sort_order": 4}
        )

过滤和排序

筛选

filter(*args, **kwargs) -> QuerySet

允许您使用跨 FK 关系的过滤器按任何模型属性/字段进行过滤以及获取实例。

Tip

排除

exclude(*args, **kwargs) -> QuerySet

与过滤器的工作原理完全相同,并且所有修饰符(后缀)都相同,但返回 not 条件。

Tip

订单依据

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

结合了基于页码和大小的偏移和限制方法。

Tip

限制

limit(limit_count: int) -> QuerySet

您可以将结果限制为所需的父模型数量。

Tip

抵消

offset(offset: int) -> QuerySet

您可以通过所需的主模型数量来抵消结果。

Tip

选择列的子集

领域

fields(columns: Union[List, str, set, dict]) -> QuerySet

使用 fields(),您可以选择模型列的子集来限制数据负载。

Tip

排除字段

exclude_fields(columns: Union[List, str, set, dict]) -> QuerySet

使用 except_fields(),您可以选择将排除的模型列的子集以限制数据加载。

!!!tip 在查询文档中了解更多信息 except_fields

聚合函数

数数

count(distinct: bool = True) -> int

返回与给定条件匹配的行数(即应用过滤器和排除)

Tip

存在

存在() -> 布尔值

返回一个布尔值以确认是否有符合给定条件的行(与过滤器和排除一起应用)

Tip