最近刚开始学 python 和 fastapi, 按照 fastapi 教程学习时遇到个问题, 因为使用 sqlmodel 的 relationship, 导致两个模型文件相互导入, 然后报错了, 根据官方文档的解决办法, 使用 TYPE_CHECKING 和字符串版本类型后暂时解决了报错.
但是当接口通过 response_model 指定了数据模型(非表模型)作为返回类型时, 又出现了报错, 报错提示如下:
`TypeAdapter[typing.Annotated[app.models.teams.TeamPublicWithUser, FieldInfo(annotation=TeamPublicWithUser, required=True)]]` is not fully defined; you should define `typing.Annotated[app.models.teams.TeamPublicWithUser, FieldInfo(annotation=TeamPublicWithUser, required=True)]` and all referenced types, then call `.rebuild()` on the instance.
求各位大佬帮忙看看, 哪里有问题.
python 版本用的是 3.12, 具体代码如下
models/users.py
from typing import TYPE_CHECKING, Any, Optional
from sqlmodel import Field, Relationship, SQLModel
if TYPE_CHECKING:
from .teams import Team, TeamPublic
class UserBase(SQLModel):
username: str = Field(index=True, max_length=255, unique=True)
email: str | None = Field(default=None, index=True, max_length=255)
is_active: bool = True
is_superuser: bool = False
full_name: str | None = Field(default=None, max_length=255)
team_id: int | None = Field(default=None, foreign_key="team.id")
class User(UserBase, table=True):
id: int | None = Field(default=None, primary_key=True)
hashed_password: str
team: Optional["Team"] = Relationship(back_populates="members")
class UserPublic(UserBase):
id: int
class UserPublicWithTeam(UserPublic):
team: Optional["TeamPublic"] = None
models/teams.py
from typing import TYPE_CHECKING, Any, List
from sqlmodel import Field, Relationship, SQLModel
if TYPE_CHECKING:
from .users import User, UserPublic
class TeamBase(SQLModel):
name: str = Field(max_length=255)
class Team(TeamBase, table=True):
id: int | None = Field(default=None, primary_key=True)
members: List["User"] = Relationship(back_populates="team")
class TeamPublic(TeamBase):
id: int
class TeamPublicWithUser(TeamPublic):
members: List["UserPublic"] = []
router/users.py
# 用户相关接口
from sqlmodel import and_, select
from app.api.deps import SessionDep
from app.models.users import (
User,
UserPublicWithTeam,
)
from app.new_router import new_router
router = new_router(prefix="/users", tags=["用户管理"])
@router.get("/{id}", summary="获取用户详情", response_model=UserPublicWithTeam)
async def get_user_api(db: SessionDep, id: int):
user = db.exec(select(User).where(and_(User.id == id, User.is_active))).first()
return user
router/teams.py
# 团队相关接口
from sqlmodel import select
from app.api.deps import SessionDep
from app.models.teams import (
Team,
TeamPublicWithUser,
)
from app.new_router import new_router
router = new_router(prefix="/teams", tags=["团队管理"])
@router.get("/{id}", summary="获取团队详情", response_model=TeamPublicWithUser)
async def get_team_api(db: SessionDep, id: int):
team = db.exec(select(Team).where(Team.id == id)).first()
return team
1
ylei 9 小时 47 分钟前
.
├── db.py ├── main.py ├── models │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-311.pyc │ │ ├── teams.cpython-311.pyc │ │ └── users.cpython-311.pyc │ ├── teams.py │ └── users.py ├── __pycache__ │ ├── db.cpython-311.pyc │ └── main.cpython-311.pyc ├── pyproject.toml ├── README.md ├── router │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-311.pyc │ │ ├── teams.cpython-311.pyc │ │ └── users.cpython-311.pyc │ ├── teams.py │ └── users.py ├── test.db └── uv.lock db.py from fastapi import Depends from sqlmodel import Session from typing import Generator from sqlmodel import SQLModel, create_engine DATABASE_URL = "sqlite:///./test.db" engine = create_engine(DATABASE_URL, echo=True) def get_session() -> Generator[Session, None, None]: with Session(engine) as session: yield session SessionDep = Depends(get_session) def create_db_and_tables(): SQLModel.metadata.create_all(engine) teams.py from sqlmodel import select from sqlmodel import Session from db import SessionDep from models.teams import ( Team, TeamPublicWithUser, ) from fastapi import APIRouter router = APIRouter(prefix="/teams", tags=["团队管理"]) @router.get("/{id}", summary="获取团队详情", response_model=TeamPublicWithUser) async def get_team_api(id: int, db: Session = SessionDep, ): team = db.exec(select(Team).where(Team.id == id)).first() return team |
2
ylei 9 小时 12 分钟前
我 get 到问题了是 models/teams.py 和 models/users.py 相互引用
我觉得可以从两个方面入手 1. 需求上 users.py 里的表是否可以不依赖 teams 2. 存在外键的表独立出来 users_teams.py? |
3
yingxiangyu 9 小时 10 分钟前
把循环引用的 import 放到 class 里面,不要放到文件开头
|
4
hugozach 9 小时 7 分钟前
使用依赖注入设计模式
|
5
laminux29 9 小时 5 分钟前
X-Y 问题。
从建模上来说,Team 是由 User 构成,Team 引用 User 是正确的,但 User 为什么要引用 Team ? 这明显是个建模错误,而非循环导入问题。 |