English 中文(简体)
FastAPI many to many relationship, multiple models and schemas (circular dependencies error)
原标题:

i m new with FastAPI, actually i spend much time trying solve my problem, i read many and test diferente Solutions but not working. The Problem is this:

I have a table School, my model and my schema:

model/school.py

from sqlalchemy.orm import relationship

class School(BASE):
    __tablename__ = "school"
    ...

    careers = relationship("Career", back_populates="school")

schema/school.py

from src.schemas.v1.career import Career

class School(BaseModel):
    id: Optional[int] = None
    ...
    careers: list[Career] = []
    
    class Config:
        orm_mode = True

Then my relation many to many between Career and Employee, CareerHasEmployee

models/career.py

from sqlalchemy.orm import relationship

class Career(BASE):
    __tablename__ = "career"
    ...
    school_id = Column(Integer, ForeignKey("school.id"))

    # Relations
    school = relationship("School", back_populates="careers")
    ...
    employees = relationship("Employee", secondary="career_has_employee", backref="career_employee")

models/career_has_employee.py

from sqlalchemy.orm import relationship

class CareerHasEmployee(BASE):
    __tablename__ = "career_has_employee"
    career_id = Column(Integer, ForeignKey("career.id"), primary_key=True)
    employee_id = Column(Integer, ForeignKey("employee.id"), primary_key=True)

models/employee.py

from sqlalchemy.orm import relationship

class Employee(BASE):
    __tablename__ = "employee"
    id = Column(Integer, primary_key = True)
    ...

    careers = relationship("Career", secondary="career_has_employee", backref="employee_career")

When testing the relation from consolé in Python, get data correctly, but when testing since fastapi i get error for circular dependency, this error happens when load schemas.

schemas/career.py

from src.schemas.v1.employee import Employee

class CareerBase(BaseModel):
    id: Optional[int] = None
    ...
    school_id: int

    class Config:
        orm_mode = True

class CareerEmployee(CareerBase):
    employees: list[Employee] = []

schemas/employee.py

...
from src.schemas.v1.career import Career <- When use this line i get error for circular dependency, this is because in schema/school.py already import this Schema

class EmployeeBase(BaseModel):
    id: Optional[int] = None
    ...

    class Config:
        orm_mode = True

class EmployeeCareer(EmployeeBase):
    careers: list[Career] = []

Response host/careers/{id}/employees

{
  "id": 1,
  "nombre": "Ingenieria en Sistemas Computacionales",
  "employees": [
    {
      "id": 1,
      "nombre": "Jhon",
      "apellidos": "Wick"
    },
    {
      "id": 2,
      "nombre": "Kymberly",
      "apellidos": "Thanos"
    }
  ]
}

When try this endpoint host/employees/{id}/careers

I get error for circular dependency

Note: Already i try:

  • from future import annotations and update_forward_refs for diferent ways
  • use TYPE_CHECKING
  • add all schemas in init.py and update_forward_refs and not working u.u
最佳回答

The error is given from the circular dependency that is within the schema.

That is, you are declaring that career requires to import from employee and employee to import from career. As soon as the program one of the two, it ll try to fetch the other one, which will require the first one, which requires the second one in order to resolve and so on ... it s an infinite loop.

Solution

The only solution you have is to create to base schema (one for employee and one for career) and then two other "auxiliary" schema that will be returned from your API which will contain both.

Otherwise, ask yourself if it s really necessary to return all that data...do the careers really need all the employees? Do the employees really need the careers?

Personally, I would drop the careers from the employees as this would imply to fetch a potentially huge amount of data that may not be needed.

问题回答

Thank you so much @isabi

I didn t want to create more schemas, but your solution worked for me.

schemas/career.py

class CareerBase(BaseModel):
    id: Optional[int] = None
    ...
    school_id: int

    class Config:
        orm_mode = True

schemas/career_employee.py

from src.schemas.v1.career import CareerBase
from src.schemas.v1.employee import Employee

class CareerEmployee(CareerBase):
    employees: list[Employee] = []

schemas/employee

class EmployeeBase(BaseModel):
    id: Optional[int] = None
    ...

    class Config:
        orm_mode = True

schemas/employee_career.py

from src.schemas.v1.employee import EmployeeBase
from src.schemas.v1.career import Career

class EmployeeCareer(EmployeeBase):
    careers: list[Career] = []

Then modify my routes routes/career.py

from src.schemas.v1.career import Career
from src.schemas.v1.career_employee import CareerEmployee
...

@router.get( /{id} , tags=[ careers ], response_model=Career, status_code=status.HTTP_200_OK)
def show(id: int = Path(..., title="ID", gt=0)):
    career = CareerService().show(id)
    return career

@router.get( /{id}/employees , tags=[ careers ], response_model=CareerEmployee, status_code=status.HTTP_200_OK)
def career_employees(id: int = Path(..., title="ID", gt=0)):
    career = CareerService().show(id)
    return career

router/employee

from src.schemas.v1.employee import Employee
from src.schemas.v1.employee_career import EmployeeCareer

...
@router.get( /{id} , tags=[ employees ], response_model=Employee, status_code=status.HTTP_200_OK)
def show(id: int = Path(...,title="ID", gt=0)):
    employee = EmployeeService().show(id)
    return employee

@router.get( /{id}/careers , tags=[ employees ], response_model=EmployeeCareer, status_code=status.HTTP_200_OK)
def employee_careers(id: int = Path(..., title="ID", gt=0)):
    employee = EmployeeService().show(id)
    return employee




相关问题
sqlalchemy does not create my foreign key

SqlAlchemy newbie question: Base = declarative_base() class A(Base): __tablename__ = as id = Column(Integer, primary_key=True) class B(Base): __tablename__ = bs id = Column(...

How to get sqlalchemy length of a string column

Consider this simple table definition (using SQLAlchemy-0.5.6) from sqlalchemy import * db = create_engine( sqlite:///tutorial.db ) db.echo = False # Try changing this to True and see what happens ...

Can SQLAlchemy update the table structure?

I am working on my first pylons + SQLAlchemy app (I m new to both). As I change my mind on the table structure, I wish there was a similar function to metadata.create_all(), that checks if there are ...

SQLAlchemy 0.5.5 - defining table schema

I used sqlautocode to generate a model.py for an existing MySQL database and here s a table example: fusion_articles = Table( fusion_articles , metadata, Column(u article_id , Integer(), ...

热门标签