Я использую full-stack-fastapi-postgresql, fastapi версии 0.54.1 и pydantic версия 1.4.
Я понятия не имею, как настроить pydantic, поэтому он правильно работает с двунаправленными отношениями «многие к одному» в SQLAlchemy. По какой-то причине моя текущая реализация взрывает стек с максимальной ошибкой рекурсии.
Мне известно об обсуждении на github. from_orm () должен определять циклы при загрузке двунаправленных отношений SQLAlchemy, а не взорвать стек. Я считаю, что это тесно связано, но пока я не смог сделать из этого ничего полезного.
Любая помощь будет принята с благодарностью.
Сообщение об ошибке от fastAPI:
Файл /usr/local/lib/python3.7/site-packages/fastapi/encoders.py, строка 113, в jsonable_encoder sqlalchemy_safe = sqlalchemy_safe, Файл /usr/local/lib/python3.7/site-packages/fastapi/encoders .py, строка 166, в jsonable_encoder sqlalchemy_safe = sqlalchemy_safe, File /usr/local/lib/python3.7/site-packages/fastapi/encoders.py, строка 52, в jsonable_encoder, если isinstance (obj, BaseModel): File / usr /local/lib/python3.7/abc.py, строка 139, в instancecheck return _abc_instancecheck (cls, instance) RecursionError: максимальная глубина рекурсии превышена при сравнении
Модели:
app / models / company.py
from typing import TYPE_CHECKING
from sqlalchemy import Boolean, Column, Integer, String
from sqlalchemy.orm import relationship
from app.db.base_class import Base
if TYPE_CHECKING:
from .company import Company # noqa: F401
class Company(Base):
id = Column(Integer, primary_key=True, index=True)
enabled = Column(Boolean(), default=True)
logourl = Column(String, index=True)
name = Column(String, index=True)
users = relationship("User", back_populates="company")
app / models / user.py
from typing import TYPE_CHECKING
from sqlalchemy import Column, ForeignKey, Integer, String, Boolean, PrimaryKeyConstraint,UniqueConstraint, DateTime
from sqlalchemy.orm import relationship
from app.db.base_class import Base
if TYPE_CHECKING:
from .job import Job # noqa: F401
from .company import Company # noqa: F401
class User(Base):
id = Column(Integer, primary_key=True, index=True)
full_name = Column(String, index=True)
email = Column(String, unique=True, index=True, nullable=False)
hashed_password = Column(String, nullable=False)
is_active = Column(Boolean(), default=True)
is_superuser = Column(Boolean(), default=False)
company_id = Column(Integer, ForeignKey("company.id"))
company = relationship("Company", back_populates="users")
Схемы:
app / schemas / user.py
from typing import Optional, Any
from pydantic import BaseModel, EmailStr
# Shared properties
class UserBase(BaseModel):
email: Optional[EmailStr] = None
is_active: Optional[bool] = True
is_superuser: bool = False
full_name: Optional[str] = None
company_id: Optional[int] = None
company: Optional[Any] = None
# Properties to receive via API on creation
class UserCreate(UserBase):
email: EmailStr
password: str
company_id: int
# Properties to receive via API on update
class UserUpdate(UserBase):
password: Optional[str] = None
company_id: Optional[int] = None
class UserInDBBase(UserBase):
id: Optional[int] = None
class Config:
orm_mode = True
# Additional properties to return via API
class User(UserInDBBase):
pass
# Additional properties stored in DB
class UserInDB(UserInDBBase):
hashed_password: str
app / schemas / company.py
from typing import Optional, List
from pydantic import BaseModel
from .user import User
# Shared properties
class CompanyBase(BaseModel):
enabled: Optional[bool] = None
logourl: Optional[str] = None
name: Optional[str] = None
users: List[User] = None
# Properties to receive on Company creation
class CompanyCreate(CompanyBase):
name: str
# Properties to receive on Company update
class CompanyUpdate(CompanyBase):
pass
# Properties shared by models stored in DB
class CompanyInDBBase(CompanyBase):
id: int
name: str
class Config:
orm_mode = True
# Properties to return to client
class Company(CompanyInDBBase):
pass
# Properties properties stored in DB
class CompanyInDB(CompanyInDBBase):
pass