Частный аргумент Pydantic для создания экземпляра рекурсивной модели

#python #pydantic

Вопрос:

У меня есть модель Pydantic, которая в основном представляет собой список других моделей, таких как:

 
class Thing(BaseModel):
    _api: Api = PrivateAttr()
    id: int
    name: str

class ThingList(BaseModel):
    _api: API = PrivateAttr()
    __root__ = List[Thing]

 

Эти вещи анализируются из содержимого JSON вызовов API, которые я выполняю для внешнего API, например:

 def some_method_somewhere(self, api, **other_args)
    ...
    response = await api.send('GET', url)
    return ThingList(__root__=response, api=api)
 

Однако я не вижу, как я могу заставить экземпляр Thing модели Pydantic получить api аргумент.

Единственный простой способ , который я вижу, — это чтобы какая-то функция возвращала глобальное значение, из которого я могу позвонить PrivateAttr(default_factory=func) , но это пахнет.

Эта функциональность должна быть как можно более общей. В настоящее время список вещей можно заменить обычным списком, выполнив итерацию по объекту ответа (не стесняйтесь притворяться, что он исходит из запросов), но это не гарантируется в будущем. (На самом деле, вполне вероятно, что другие атрибуты будут поступать из API, которые, возможно, потребуется интегрировать в ThingList).

Решением моей мечты было бы расширение метода где-нибудь в классе ThingList, но я не могу найти, как это делает Pydantic.

Ответ №1:

Вы можете обновить частные атрибуты вложенных объектов в __init__ методе включения модели:

 class Thing(BaseModel):
    _api: str = PrivateAttr()
    id: int
    name: str


class ThingList(BaseModel):
    _api: str = PrivateAttr()
    __root__: List[Thing]

    def __init__(self, *, api, **data):
        super().__init__(**data)
        self._api = api
        for item in self.__root__:
            item._api = api
 

Комментарии:

1. Это многообещающе. Однако не возникнет ли у меня проблем с валидаторами, потому что его не существует при инициализации?

2. Возможно, в случае валидаторов было бы неплохо увидеть минимальный пример вашего варианта использования.

3. Я думал о валидаторах pydantic по умолчанию. Но я запустил код с вашим предложением, и они не жалуются на назначение после создания экземпляра. Так что все в порядке.