繁体   English   中英

如何从同一个 class 中的一个字段引用另一个 Pydantic 字段?

[英]How to reference another Pydantic field from a field within the same class?

我试图将一个字段的长度引用为 Pydantic 中同一个 class 中另一个字段的默认值,但不确定如何实现它。

在这种特殊情况下,我希望payload_length给我payload_body的长度,以便在长度大于 250 字节时验证失败。

然而,python 告诉我payload_body没有定义,因为它是同一个 pydantic class 的一部分。

有什么建议么?

class Downlink(BaseModel):

    payload_id: str = Field(
        default_factory=lambda: str(uuid4()),
        repr=False,
        exclude=False
        )

    payload_body: str = Field(
        repr=True
        )

    payload_length: int = Field(
        default_factory=lambda: len(payload_body),
        le=250,
        repr=True
        )

    created_at: str = Field(
        default_factory=lambda: str(datetime.datetime.now()),
    )


downlink = Downlink(payload_body="This is a test of a long Downlink message that should be less than 250 bytes in length.")

logger.debug(f"Downlink created. {downlink.dict()}")

答案由Gino Mempin提供。

使用 Pydantics @root_validator有效。 这是完整的解决方案:

class Downlink(BaseModel):

    payload_id: UUID = Field(
        default_factory=uuid4,
        )

    payload_body: str = Field(
        repr=True
        )

    created_at: datetime = Field(
        default_factory=datetime.now
        )

    _payload_length: int = Field(
        ge=1,
        le=250,
    )

    ## Function to automatically generate the payload_length field
    @root_validator
    def get_payload_length(cls, values):
        length = len(values['payload_body'])
        if length > 250:
            logger.error(f"Payload length cannot exceed 250 bytes. Payload length: {length} bytes.")
            raise ValueError("Payload length cannot exceed 250 bytes.")
        else:
            values['_payload_length'] = length
        return values


downlink = Downlink(payload_body="*" * 260)

logger.debug(f"Downlink created. {downlink.dict()}")

结果:

2022-12-31 11:18:51:881 ERROR | Payload length cannot exceed 250 bytes. Payload length: 260 bytes.

downlink = Downlink(payload_body="*" * 260)切换为downlink = Downlink(payload_body="*" * 10)通过验证:

2022-12-31 11:22:13:522 DEBUG | Downlink created. {'payload_id': UUID('f0bd0126-f855-4d2e-9b01-f6dc32c05932'), 'payload_body': '**********', 'created_at': datetime.datetime(2022, 12, 31, 11, 22, 13, 522130), '_payload_length': 10}

尝试使用带有pre关键字参数的root_validator来计算payload_body的长度。

import datetime
import typing
from uuid import uuid4

from pydantic import BaseModel, ValidationError, root_validator


class Downlink(BaseModel):
    payload_id: str = Field(
        default_factory=lambda: str(uuid4()), repr=False, exclude=False
    )
    payload_body: str = Field(repr=True)
    payload_length: int = Field(default=0, le=250, repr=True)
    created_at: str = Field(
        default_factory=lambda: str(datetime.datetime.now()),
    )

    @root_validator(pre=True)
    @classmethod
    def set_payload_length(cls, values: typing.Dict):
        if values.get("payload_body", ""):
            values.update({"payload_length": len(values["payload_body"])})
        return values


downlink = Downlink(
    payload_body="This is a test of a long Downlink message that should be less than 250 bytes in length."
)
print(f"Downlink created. {downlink.dict()}")
try:
    downlink = Downlink(
        payload_body="This is a test of a long Downlink message that should be less than 250 bytes in length."
        * 10
    )
except ValidationError as e:
    print(f"An error should occur: {e=}")
    raise e

output:

Downlink created. {'payload_id': '8feb02b2-f28e-4f2b-b75f-0bd4bde887bb', 'payload_body': 'This is a test of a long Downlink message that should be less than 250 bytes in length.', 'payload_length': 87, 'created_at': '2023-01-02 17:41:12.693928'}

pydantic.error_wrappers.ValidationError: 1 validation error for Downlink
payload_length
  ensure this value is less than or equal to 250 (type=value_error.number.not_le; limit_value=250)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM