Pydantic from_orm для загрузки модели django prefetch_related list field
У меня есть модель django:
class Foo(models.Model):
id: int
name = models.TextField(null=False)
class Bar(models.Model):
id: int
foo = models.ForeignKey(
Foo,
on_delete=models.CASCADE,
null=False,
related_name="bars",
)
и пидантическая модель как (orm_mode
есть True
):
class BarPy(BaseModel):
id: int
foo_id: int
class FooPy(BaseModel):
id: int
name: str
bars: List[BarPy]
Теперь я хочу сделать запрос к модели Foo
и загрузить ее в FooPy
, поэтому я написал такой запрос:
foo_db = Foo.objects.prefetch_related("bars").all()
pydantic_model = FooPy.from_orm(foo_db)
Но это дает мне эту ошибку:
pydantic.error_wrappers.ValidationError: 1 validation error for FooPy
bars
value is not a valid list (type=type_error.list)
У меня получается сделать это при явном использовании конструктора FooPy
и присвоении значений вручную, но я хочу использовать from_orm
.
Атрибут bars
на вашей модели Foo
- это ReverseManyToOneDescriptor
, который просто возвращает RelatedManager
для модели Bar
. Как и для любого менеджера в Django, чтобы получить набор всех экземпляров, управляемых им, вам нужно вызвать метод all
для него. Обычно вы делаете что-то вроде foo.bars.all()
.
Вы можете добавить собственный пользовательский валидатор к FooPy
и заставить его pre=True
захватывать все связанные Bar
экземпляры и передавать их последовательность валидаторам по умолчанию:
from django.db.models.manager import BaseManager
from pydantic import BaseModel, validator
...
class FooPy(BaseModel):
id: int
name: str
bars: List[BarPy]
@validator("bars", pre=True)
def get_all_from_manager(cls, v: object) -> object:
if isinstance(v, BaseManager):
return list(v.all())
return v
Обратите внимание, что недостаточно просто сделать .all()
, потому что это вернет кверисет, который не пройдет валидатор последовательности по умолчанию, встроенный в модели Pydantic. Вам нужно передать ему фактическую последовательность (например, list
или tuple
), которой QuerySet
не является.