#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
, если вы просто хотите сгенерировать значение для одного поля.
Есть два важных аспекта этого подхода, которые необходимо учитывать:
- «Ранее проверенные поля» из документации означают, что в вашем случае
private_key
они должны быть определены ранееaddress
. Значения полей, определенных после проверяемого поля, недоступны для средства проверки. - Если проверяемое поле имеет значение по умолчанию, и вы все равно хотите, чтобы в этом случае выполнялся валидатор, вы должны использовать
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
Не уверен, что это лучший способ достичь этого, хотя