Установка значения по умолчанию на основе другого значения

#python #pydantic

#питон #пидантический

Вопрос:

У меня есть следующая пидантическая модель:

 from pydantic import BaseModel
import key

class Wallet(BaseModel):
    private_key: str = Field(default_factory=key.generate_private_key)
    address: str
 

Я хочу, чтобы address имел default_factory как функцию, которая принимает private_key в качестве входных данных и возвращает адрес. Мои намерения были бы примерно следующими:

 address: str = Field(default_factory=key.generate_address(self.private_key)
 

Как я могу этого добиться?

Ответ №1:

Другой вариант — просто использовать @validator , потому что в нем вы можете получить доступ к ранее проверенным полям. Из документации:

  • валидаторы являются «методами класса», поэтому первое значение аргумента, которое они получают, — это класс UserModel, а не экземпляр UserModel .
  • вторым аргументом всегда является значение поля для проверки; его можно назвать так, как вам заблагорассудится
  • вы также можете добавить в подпись любое подмножество следующих аргументов (имена должны совпадать).:
    • values : диктант, содержащий сопоставление имени и значения любых ранее проверенных полей

Пример:

 class Wallet(BaseModel):
    private_key: str = Field(default_factory=key.generate_private_key)
    address: str = "" # "" seems better than None to use the correct type

    @validator("address", always=True)
    def get_address(cls, address: str, values: Dict[str, Any]) -> str:
        if address is None:
            return key.generate_address(values["private_key"])
        return address
 

Можно утверждать, что @validator это должно быть предпочтительнее @root_validator , если вы просто хотите сгенерировать значение для одного поля.

Есть два важных аспекта этого подхода, которые необходимо учитывать:

  1. «Ранее проверенные поля» из документации означают, что в вашем случае private_key они должны быть определены ранее address . Значения полей, определенных после проверяемого поля, недоступны для средства проверки.
  2. Если проверяемое поле имеет значение по умолчанию, и вы все равно хотите, чтобы в этом случае выполнялся валидатор, вы должны использовать always=True .

Ответ №2:

Я смог получить его с помощью root_validator :

 class Wallet(BaseModel):
    address: str = None
    private_key: str = Field(default_factory=key.generate_private_key)

    @root_validator
    def get_address(cls, values) -> dict:
        if values.get("address") is None:
            values["address"] = key.generate_address(values.get("private_key"))
        return values
 

Не уверен, что это лучший способ достичь этого, хотя