简体   繁体   中英

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

I'm trying to reference the length of one field as a default value for another field in the same class in Pydantic, but not sure how to achieve it.

In this particular case, I want the payload_length to give me the length of the payload_body so that it fails validation if the length is greater than 250 bytes.

However, python is telling me that payload_body is not defined because it's part of the same pydantic class.

Any suggestions?

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

The answer was provided by Gino Mempin .

Using Pydantics @root_validator worked. Here's the full solution:

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

Result:

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

Switching downlink = Downlink(payload_body="*" * 260) to downlink = Downlink(payload_body="*" * 10) passes validation:

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}

try using root_validator with pre keyword argument to compute length of 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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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