此GET端点不起作用:
GET
@app.get("/question/", response_model=list[schemas.QuizSchema]) def get_questions(db: Session = Depends(get_db)): quiz = db.query(models.Quiz).all() return jsonable_encoder(quiz)
它会引发以下错误:
raise ValidationError(errors, field.type_) pydantic.error_wrappers.ValidationError: 3 validation errors for QuizSchema response -> 0 -> category field required (type=value_error.missing) response -> 0 -> answer field required (type=value_error.missing) response -> 0 -> question field required (type=value_error.missing)
但是这段代码工作得很好:
@app.get("/question/", response_model=list[schemas.QuizSchema]) def get_questions(db: Session = Depends(get_db)): quiz = db.query(models.Quiz).all() for x in quiz: print(x.id, x.category.id, x.answer[0].id, x.question.id) return jsonable_encoder(quiz)
我真的不明白这是怎么回事。
我在for-loop 之前和之后使用了一个断点:
for
@app.get("/question/", response_model=list[schemas.QuizSchema]) def get_questions(db: Session = Depends(get_db)): quiz = db.query(models.Quiz).all() breakpoint() for x in quiz: print(x.id, x.category.id, x.answer[0].id, x.question.id) breakpoint() return jsonable_encoder(quiz)
那是结果:
# FIRST BREAKPOINT (Pdb) quiz [<models.Quiz object at 0x7fb81957c5e0>] (Pdb) jsonable_encoder(quiz) [{'id': 2}] (Pdb) continue 2 3 1 1 > /backend/main.py(29)get_questions() -> return jsonable_encoder(quiz) #SECOND BREAKPOINT (Pdb) quiz [<models.Quiz object at 0x7fb81957c5e0>] (Pdb) jsonable_encoder(quiz) [{'id': 2, 'category': {'quiz_category_id': 2, 'id': 3, 'name': 'foo'}, 'answer': [{'name': 'zdecydowanie nie', 'value': -2, 'id': 1}, {'name': 'raczej nie', 'value': -1, 'id': 2}, {'name': 'nie wiem', 'value': 0, 'id': 3}, {'name': 'raczej tak', 'value': 1, 'id': 4}, {'name': 'zdecydowanie tak', 'value': 2, 'id': 5}], 'question': {'name': 'bar', 'quiz_question_id': 2, 'id': 1}}] (Pdb)
我的 SQLAlchemy 模型如下所示:
class Quiz(Base): __tablename__ = "quiz" id: Mapped[int] = mapped_column(Integer, primary_key=True) category: Mapped["Category"] = relationship(back_populates="quiz_category") answer: Mapped[list[Answer]] = relationship(secondary=quiz_answer) question: Mapped["Question"] = relationship(back_populates="quiz_question")
根据你提供的信息,看起来问题可能与 Pydantic 模型的验证有关。错误消息表明在 QuizSchema 模型中,category、answer 和 question 字段被标记为必需字段,但在返回的数据中缺少这些字段。
QuizSchema
category
answer
question
在你的代码中,你使用了 SQLAlchemy 的模型来定义数据库结构,并与 Pydantic 模型一起使用来定义 API 的输入和输出。由于 Pydantic 模型具有验证功能,如果模型中的字段缺失或类型不匹配,将引发 ValidationError。
ValidationError
根据你提供的断点信息,当你在第一个断点处查看 jsonable_encoder(quiz) 的结果时,只返回了 {'id': 2},而缺少了其他字段。然而,在第二个断点处,jsonable_encoder(quiz) 返回了完整的包含所有字段的结果。
jsonable_encoder(quiz)
{'id': 2}
这可能是由于你的 SQLAlchemy 模型的延迟加载(lazy loading)特性引起的。在第一个断点处,当你访问 quiz 对象时,只有 id 字段被立即加载,而其他关联对象(如 category、answer 和 question)是延迟加载的。因此,Pydantic 在验证时无法找到这些字段,引发了验证错误。
quiz
id
要解决这个问题,你可以考虑在查询 quiz 对象时,使用 SQLAlchemy 的 options 来显式加载关联对象。例如,使用 options 的 joinedload 方法加载关联对象,以确保在验证期间这些字段也被加载:
options
joinedload
from sqlalchemy.orm import joinedload quiz = db.query(models.Quiz).options( joinedload(models.Quiz.category), joinedload(models.Quiz.answer), joinedload(models.Quiz.question) ).all()
这样,在使用 jsonable_encoder(quiz) 时,所有关联字段都将被加载,并且可以在 Pydantic 模型验证期间找到它们。
另外,请确保你的 SQLAlchemy 模型中的字段与 Pydantic 模型中的字段名称完全匹配,包括大小写。验证错误也可能是由于字段名称不匹配导致的。
模式应该有它应该有的配置类orm_mode = True:
orm_mode = True
class QuizSchema(BaseModel): .... field class Config(): orm_mode = True