Skip to content

关系

目前ormar支持两种类型的关系:

  • 与foreignkey字段的一对多(和多对一)
  • 具有 ManyToMany 字段的多对多

您可以在下面找到每个关系的非常基本的定义示例。

要了解有关方法、可能性、定义等的更多信息,请阅读文档的后续部分。

外键

要定义多对一关系,请使用外键字段。

 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
from typing import Dict, Optional, Union

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 Department(ormar.Model):
    ormar_config = ormar_base_config.copy()

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Course(ormar.Model):
    ormar_config = ormar_base_config.copy()

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    department: Optional[Union[Department, Dict]] = ormar.ForeignKey(Department)

!!!提示要了解有关一对多关系的更多信息,请访问外键部分

反向外键

一对多关系的定义也使用ForeignKey,它会自动为您注册。

因此,就上面的例子而言。

1
2
3
4
5
6
7
8
class Department(ormar.Model):
    ormar_config = base_ormar_config.copy()

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    # there is a virtual field here like follows
    courses: Optional[List[Course]] = ormar.ForeignKey(Course, virtual=True)
    # note that you DO NOT define it yourself, ormar does it for you.

!!!tip 要了解有关多对一关系的更多信息(即更改生成字段的名称),请访问外键部分

!!!tip ReverseforeignKey允许您使用queryset-proxy查询相关模型。

1
It allows you to use `await department.courses.all()` to fetch data related only to specific department etc.

多对多

要定义多对多关系,请使用 ManyToMany 字段。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
class Category(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
        tablename="categories",
    )

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=40)

class Post(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    title: str = ormar.String(max_length=200)
    categories: Optional[List[Category]] = ormar.ManyToMany(Category)

!!!提示要了解有关多对多关系的更多信息,请访问多对多部分

!!!tip ManyToMany 允许您使用 queryset-proxy 查询相关模型。

1
It allows you to use `await post.categories.all()` but also `await category.posts.all()` to fetch data related only to specific post, category etc.

穿过田野

作为 ManyToMany 关系的一部分,您可以定义一个直通模型,该模型可以包含可用于过滤、排序等的其他字段。像这样定义的字段将在 m2m 模型的当前查询的反面公开。

因此,如果从模型 A 查询到模型 B,则只有模型 B 暴露了 through 字段。哪种有意义,因为它是每个相关模型的单向模型/字段。

 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
class Category(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
        tablename="categories",
    )

    id = ormar.Integer(primary_key=True)
    name = ormar.String(max_length=40)

# you can specify additional fields on through model
class PostCategory(ormar.Model):
    ormar_config = ormar.OrmarConfig(
        database=database,
        metadata=metadata,
        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.OrmarConfig(
        database=database,
        metadata=metadata,
    )

    id: int = ormar.Integer(primary_key=True)
    title: str = ormar.String(max_length=200)
    categories = ormar.ManyToMany(Category, through=PostCategory)

!!!tip 要了解有关多对多关系和字段的更多信息,请访问多对多部分

!!!tip ManyToMany 允许您使用 queryset-proxy 查询相关模型。

1
It allows you to use `await post.categories.all()` but also `await category.posts.all()` to fetch data related only to specific post, category etc.

关系默认排序顺序

默认情况下,关系遵循模型默认排序顺序,因此 Primary_key 列升序,或 ormar_config 对象中的任何排序顺序。

!!!提示要了解有关模型排序顺序的更多信息,请访问文档的模型部分

但是您可以通过向关系提供orders_by 和 related_orders_by 参数来修改查询期间加载相关模型的顺序。

在关系中,您只能按直接相关的模型列进行排序,或者对于多对多列也可以通过模型列进行排序 {through_field_name}__{column_name}

示例配置可能如下所示:

 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
database = databases.Database(DATABASE_URL)
metadata = sqlalchemy.MetaData()


base_ormar_config = ormar.OrmarConfig(
    database=database,
    metadata=metadata,
)


class Author(ormar.Model):
    ormar_config = base_ormar_config.copy()

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)


class Book(ormar.Model):
    ormar_config = base_ormar_config.copy()

    id: int = ormar.Integer(primary_key=True)
    author: Optional[Author] = ormar.ForeignKey(
        Author, orders_by=["name"], related_orders_by=["-year"]
    )
    title: str = ormar.String(max_length=100)
    year: int = ormar.Integer(nullable=True)
    ranking: int = ormar.Integer(nullable=True)

现在调用:

await Author.objects.select_related("books").get() - 书籍将按书籍年份降序排序

await Book.objects.select_related("author").all() - 作者将按作者姓名升序排序

自参考和推迟参考

为了创建自动关系或创建两个在至少两种不同关系中相互引用的模型(请记住,反面是自动为您注册的),您需要使用输入模块中的 ForwardRef 。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
PersonRef = ForwardRef("Person")


class Person(ormar.Model):
    ormar_config = base_ormar_config.copy()

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    supervisor: PersonRef = ormar.ForeignKey(PersonRef, related_name="employees")


Person.update_forward_refs()

!!!提示要了解有关自引用和推迟关系的更多信息,请访问推迟注释部分