我正在使用 Fast API 和 SQL Alchemy 尝试向 Postgres SQL 数据库中的“Player”表发出发布请求。但是,我的玩家表出现以下错误: (https://i.sstatic.net/0k9ulaYC.png)
500:内部服务器错误:AttributeError 类型的对象不可 JSON 序列化
这让我很困惑,因为我的 Questions 和 Choices 表工作得很好,没有任何问题。我尝试创建另一个类似的表,但不断收到相同的问题,有人可以帮忙吗?
这是我的模型.py:
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from database import Base
class Players(Base):
__tablename__ = "players"
id = Column(Integer, primary_key=True)
user_name = Column(String, index=True)
# hashed_password = Column(String)
# is_active = Column(Boolean, default=True)
# items = relationship("Item", back_populates="owner")
class Questions(Base):
__tablename__ = 'questions'
#id (Eg: 69420)
#question = Have u seen my scrunchie?
id = Column(Integer, primary_key=True, index=True)
question_text = Column(String, index=True)
# answer = Column(String)
class Choices(Base):
__tablename__ = 'choices'
# id
#choices: A: yes, B: No
#is_correct: True/False
#question_id: foreign key to questions table
id = Column(Integer, primary_key=True, index=True)
choice_text = Column(String, index=True)
#column with answer either True/False
is_correct = Column(Boolean, default=False)
#Links back to question (Eg: 69420)
question_id = Column(Integer, ForeignKey("questions.id"))
# class User(Base):
# __tablename__ = "users"
# id = Column(Integer, primary_key=True, index=True)
这是我的 main.py
from fastapi import FastAPI, HTTPException, Depends, Request
from pydantic import BaseModel
from typing import List, Annotated
from fastapi.exceptions import RequestValidationError
from fastapi.responses import PlainTextResponse
import models, crud, schemas
from database import engine, SessionLocal
from sqlalchemy.orm import Session
from starlette.exceptions import HTTPException
from fastapi.exceptions import RequestValidationError
from exception_handlers import request_validation_exception_handler, http_exception_handler, unhandled_exception_handler
from middleware import log_request_middleware
app = FastAPI()
app.middleware("http")(log_request_middleware)
app.add_exception_handler(RequestValidationError, request_validation_exception_handler)
app.add_exception_handler(HTTPException, http_exception_handler)
app.add_exception_handler(Exception, unhandled_exception_handler)
models.Base.metadata.create_all(bind=engine)
class PlayerBase(BaseModel):
user_name: str
#Model rep the choice user makes and whether its True/False
class ChoiceBase(BaseModel):
choice_text: str
is_correct: bool
#Model rep the possible choices a user can make A, B, C, D
class QuestionBase(BaseModel):
question_text: str
choices: List[ChoiceBase]
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
db_dependency = Annotated[Session, Depends(get_db)]
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
return PlainTextResponse(str(exc), status_code=400)
@app.post("/players")
async def create_player(user: PlayerBase, db: db_dependency):
try:
db_player = models.Player(user_name=user.user_name)
db.add(db_player)
db.commit()
db.refresh(db_player)
except Exception as e:
print(e)
raise HTTPException(status_code=404, detail=e)
# @app.get("/users/", response_model=list[schemas.User])
# def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
# users = crud.get_users(db, skip=skip, limit=limit)
# return users
@app.post("/questions")
async def create_questions(question: QuestionBase, db: db_dependency):
db_question = models.Questions(question_text=question.question_text)
print("This works for some stupid reason")
db.add(db_question)
db.commit()
#Refresh
db.refresh(db_question)
for choice in question.choices:
#quick filter for db choice, look into model. choices
db_choice = models.Choices(choice_text=choice.choice_text, is_correct=choice.is_correct, question_id=db_question.id)
db.add(db_choice)
db.commit()
@app.get("/questions/{questions_id}")
async def read_question(question_id: int, db: db_dependency):
result = db.query(models.Questions).filter(models.Questions.id == question_id).first()
if not result:
raise HTTPException(status_code=404, detail='Question is not found')
return result
@app.get("/choices/{question_id}")
async def read_choices(question_id: int, db: db_dependency):
result = db.query(models.Choices).filter(models.Choices.question_id == question_id).all()
if not result:
raise HTTPException(status_code=404, detail='Choices is not found')
return result
我尝试过错误处理技术来缩小问题范围并搜索其他论坛,但我还没有找到类似的问题或解决方案
create_player
内的异常处理程序会吞下任何异常,无论该异常是什么,然后尝试将该异常序列化为 HTTP 响应的 JSON 正文:
except Exception as e:
print(e)
raise HTTPException(status_code=404, detail=e)
这意味着您永远不会出现正确的错误 - 这使得进行正确的开发变得非常困难。
您应该始终明确要捕获的异常,而不是捕获任何异常,然后将该异常暴露给调用您的 API 的任何人(这也是一个坏主意,因为您最终可能会泄漏您不想要的信息公开)。
如果删除整个
try
和 except
部分,您可能会发现您输错了模型名称:它的名称为 Players
而不是您要访问的 Player
,因此当您尝试在 AttributeError
模块中引用 Player
时,您会得到一个 models
。
将您的
Players
模型重命名为 Player
(在这种情况下,将所有其他模型从复数重命名为单数,如果它们也代表单数条目),或者更改您的引用以引用正确的模型名称:
db_player = models.Players(user_name=user.user_name)