【问题标题】:How to properly setup a One To Many bidirectional relationship using fastAPI, Pydantic and SQLAlchemy如何使用 fastAPI、Pydantic 和 SQLAlchemy 正确设置一对多双向关系
【发布时间】:2021-03-14 15:42:34
【问题描述】:

我使用full-stack-fastapi-postgresql,fastapi 版本 0.54.1 和 pydantic 版本 1.4。

我不知道如何设置 pydantic,因此它可以在 SQLAlchemy 中与多对一双向关系正常工作。出于某种原因,我当前的实现以最大递归错误破坏了堆栈。

我知道一个 github 讨论 from_orm() should detect cycles when loading SQLAlchemy bi-directional relationships rather than blow stack 。我相信这是密切相关的,但到目前为止我无法从中做出任何有用的事情。

任何帮助将不胜感激。

来自 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,文件“/usr/local/lib/python3.7/site-packages/fastapi/encoders.py”,第 52 行, 在 jsonable_encoder if isinstance(obj, BaseModel): instancecheck 中的文件“/usr/local/lib/python3.7/abc.py”,第 139 行 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

【问题讨论】:

  • 如果您在处理 FastAPI/Pydantic/SQLAlchemy 集成方面需要更多帮助,请随时告诉我,我已经与该堆栈进行了相当多的交互。希望我的回答能解决问题。

标签: python sqlalchemy fastapi pydantic


【解决方案1】:

您试图让user 架构包含company,但还希望company 架构包含user,这意味着当您检索特定公司时,例如,其用户将包含同一家公司,并且该公司将再次包含所有用户,因此存在递归问题。

您需要决定在检索到 usercompany 时要显示哪些数据,如果您只想检索具体user

解决方案

UserBase 架构中删除company 就足够了。

【讨论】:

    猜你喜欢
    • 2021-09-24
    • 2021-04-15
    • 2015-02-14
    • 2022-01-25
    • 2021-11-01
    • 2021-11-21
    • 2020-11-17
    • 1970-01-01
    相关资源
    最近更新 更多