Skip to content

仅 Pydantic 字段

Ormar 允许您在其模型中声明普通 pydantic 字段,因此您可以访问所有基本和自定义 pydantic 字段,如 str、int、HttpUrl、PaymentCardNumber 等。

您甚至可以声明通向仅限嵌套 pydantic 模型的字段,而不仅仅是单个字段。

由于这些字段未存储在数据库中(这就是这些字段的全部意义),因此您必须为它们提供一个有意义的值,可以通过设置默认值或在模型初始化期间提供一个值。

如果 ormar 无法解析 pydantic 字段的值,则在从数据库加载数据期间将会失败,并且缺少声明的 pydantic 字段所需的值。

下面描述了提供值的选项。

当然,您可以将其中的一些或全部组合到一个模型中。

可选字段

如果将字段设置为可选,则如果未提供,则默认为“无”,这正是从数据库加载期间会发生的情况。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
base_ormar_config = ormar.OrmarConfig(
    metadata=sqlalchemy.MetaData(),
    database=databases.Database(DATABASE_URL),
)


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

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=200)
    number: Optional[PaymentCardNumber]

test = ModelTest(name="Test")
assert test.name == "Test"
assert test.number is None
test.number = "123456789015"

await test.save()
test_check = await ModelTest.objects.get()

assert test_check.name == "Test"
# after load it's back to None
assert test_check.number is None

具有默认值的字段

通过设置默认值,该值将在初始化和数据库加载时设置。请注意,将默认值设置为“无”与将该字段设置为“可选”相同。

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


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

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=200)
    url: HttpUrl = "https://www.example.com"

test = ModelTest(name="Test")
assert test.name == "Test"
assert test.url == "https://www.example.com"

test.url = "https://www.sdta.ada.pt"
assert test.url == "https://www.sdta.ada.pt"

await test.save()
test_check = await ModelTest.objects.get()

assert test_check.name == "Test"
# after load it's back to default
assert test_check.url == "https://www.example.com"

默认工厂功能

通过设置 default_factory 函数,函数调用的结果将在初始化和每次数据库加载时设置。

 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
33
34
35
36
37
38
39
40
41
42
43
from pydantic import Field, PaymentCardNumber
# ...


base_ormar_config = ormar.OrmarConfig(
    metadata=sqlalchemy.MetaData(),
    database=databases.Database(DATABASE_URL),
)


CARD_NUMBERS = [
    "123456789007",
    "123456789015",
    "123456789023",
    "123456789031",
    "123456789049",
]


def get_number():
    return random.choice(CARD_NUMBERS)


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

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=200)
    # note that you do not call the function, just pass reference
    number: PaymentCardNumber = Field(default_factory=get_number)

# note that you still CAN provide a value 
test = ModelTest2(name="Test2", number="4000000000000002")
assert test.name == "Test2"
assert test.number == "4000000000000002"

await test.save()
test_check = await ModelTest2.objects.get()

assert test_check.name == "Test2"
# after load value is set to be one of the CARD_NUMBERS
assert test_check.number in CARD_NUMBERS
assert test_check.number != test.number

__init__ 中的自定义设置

您可以在调用 super() init 方法之前在 __init__() 方法中为该字段提供一个值。

 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
33
34
35
36
37
38
39
40
41
from pydantic import BaseModel
# ...


base_ormar_config = ormar.OrmarConfig(
    metadata=sqlalchemy.MetaData(),
    database=databases.Database(DATABASE_URL),
)


class PydanticTest(BaseModel):
    aa: str
    bb: int


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

    # provide your custom init function
    def __init__(self, **kwargs):
        # add value for required field without default value
        kwargs["pydantic_test"] = PydanticTest(aa="random", bb=42)
        # remember to call ormar.Model init!
        super().__init__(**kwargs)

    id: int = ormar.Integer(primary_key=True)
    name: str = ormar.String(max_length=200)
    pydantic_test: PydanticTest

test = ModelTest3(name="Test3")
assert test.name == "Test3"
assert test.pydantic_test.bb == 42
test.pydantic.aa = "new value"
assert test.pydantic.aa == "new value"

await test.save()
test_check = await ModelTest3.objects.get()

assert test_check.name == "Test3"
# after load it's back to value provided in init
assert test_check.pydantic_test.aa == "random"

!!!警告如果您未以上述方式之一提供值,则在从数据库加载时将引发 ValidationError 。