Skip to content

推迟注释

自引用模型

当您想在声明期间引用相同的模型来创建关系时,您需要将引用的模型声明为 ForwardRef,因为在声明期间该类尚未准备好,并且 python 默认情况下不会让您引用它。

尽管您可能会想使用未来的注释或简单地用“”引用名称,但它不会起作用,因为 ormar 旨在与显式声明的 ForwardRef 一起使用。

首先,您需要从输入中导入所需的引用。

1
from typing import ForwardRef

现在我们需要一个示例模型和对同一模型的引用,它将用于创建自引用关系。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# create the forwardref to model Person
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)
    # use the forwardref as to parameter
    supervisor: PersonRef = ormar.ForeignKey(PersonRef, related_name="employees")

就是这么简单。但在使用模型之前,您需要手动更新引用,以便它们生成实际模型。

!!!警告如果您尝试在没有更新引用的情况下使用模型,则会引发 ModelError 异常。因此,在上面的示例中,任何像下面这样的调用都会导致异常 python # creation of model - exception await Person.objects.create(name="Test") # initialization of model - exception Person2(name="Test") # usage of model's QuerySet - exception await Person2.objects.get()

要更新引用,请仅在声明所有相关模型之后,在具有前向引用的每个模型上调用 update_forward_refs 方法。

因此,为了使我们之前的示例正常工作,我们只需要额外一行。

 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()

当然,对于 to 和 through 参数,可以以完全相同的方式对 ManyToMany 关系完成相同的操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# declare the reference
ChildRef = ForwardRef("Child")

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

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

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    # use it in relation
    friends = ormar.ManyToMany(ChildRef, through=ChildFriend,
                               related_name="also_friends")


Child.update_forward_refs()

跨模型关系

与自引用模型相同的机制和逻辑可以用于在彼此之间链接多个不同的模型。

当然,ormar 会为您链接关系的双方,使用指定(或默认)的 related_name 创建反向关系。

但是,如果您需要任何两个模型之间的两个(或多个)关系,无论出于何种原因,该关系都应存储在两侧(因此在一个模型上声明一个关系,在第二个模型上声明另一个关系),则需要使用 ForwardRef 来实现那。

看下面的简单例子。

 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
# teacher is not yet defined
TeacherRef = ForwardRef("Teacher")


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

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    # so we use reference instead of actual model
    primary_teacher: TeacherRef = ormar.ForeignKey(TeacherRef,
                                                   related_name="own_students")


class StudentTeacher(ormar.Model):
    ormar_config = base_ormar_config.copy(tablename='students_x_teachers')


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

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=100)
    # we need students for other relation hence the order
    students = ormar.ManyToMany(Student, through=StudentTeacher,
                                related_name="teachers")

# now the Teacher model is already defined we can update references
Student.update_forward_refs()

!!!警告请记住,无论定义了多少个关系,related_name 在相关模型中都必须是唯一的。