I use full-stack-fastapi-postgresql, fastapi version 0.54.1 and pydantic version 1.4.
I have no idea how to setup pydantic, so it properly works with a many to one bidirectional relationship in SQLAlchemy. For some reason, my current implementation blows the stack with a maximum recursion error.
I am aware of a github discussion from_orm() should detect cycles when loading SQLAlchemy bi-directional relationships rather than blow stack . I believe this is closely related, but I could not make anything useful out of it so far.
Any help would be greatly appreciated.
Error message from fastAPI:
File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 113, in jsonable_encoder sqlalchemy_safe=sqlalchemy_safe, File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 166, in jsonable_encoder sqlalchemy_safe=sqlalchemy_safe, File "/usr/local/lib/python3.7/site-packages/fastapi/encoders.py", line 52, in jsonable_encoder if isinstance(obj, BaseModel): File "/usr/local/lib/python3.7/abc.py", line 139, in instancecheck return _abc_instancecheck(cls, instance) RecursionError: maximum recursion depth exceeded in comparison
The models:
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")
The schemas:
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