FastAPI+SQLAlchemy删除数据报错:int对象无_sa_instance_state属性
FastAPI删除接口SQLAlchemy错误解决方法
问题描述
在FastAPI中实现删除博客的接口时,出现以下错误:
AttributeError: 'int' object has no attribute '_sa_instance_state' The above exception was the direct cause of the following exception: sqlalchemy.orm.exc.UnmappedInstanceError: Class 'builtins.int' is not mapped
对应代码如下:
from fastapi import FastAPI, Depends, status from sqlalchemy.orm import Session from typing import List from database import engine, SessionLocal from models import Blog, User from fastapi import HTTPException import schemas,models app = FastAPI() def getdb(): db = SessionLocal() try: yield db finally: db.close models.Base.metadata.create_all(engine) #migrating @app.get('/blog') def all_blogs(db: Session = Depends(getdb)): db_blog = db.query(Blog).all() return db_blog @app.get('/user') def all_users(db: Session = Depends(getdb)): db_blog= db.query(User).all() return db_blog @app.post('/blog', status_code= status.HTTP_201_CREATED) def create_blog(blog: schemas.BlogCreate, db: Session = Depends(getdb)): db_blog = Blog(title=blog.title, user_id = blog.user_id) db.add(db_blog) db.commit() db.refresh(db_blog) return db_blog @app.post('/user', status_code= status.HTTP_201_CREATED) def create_user(user: schemas.UserCreate, db: Session = Depends(getdb)): db_user = User(name = user.name) db.add(db_user) db.commit() db.refresh(db_user) return db_user @app.delete('/blog/{blog_id}', status_code= status.HTTP_204_NO_CONTENT) def destroy(blog_id, db:Session = Depends(getdb)): db_blog = db.query(Blog).filter(Blog.id == blog_id).delete(synchronize_session="evaluate") db.commit() db.refresh(db_blog) return f"{Blog.id} deleted" @app.get('/blog/{blog_id}', response_model=schemas.Blog) def show_blog(blog_id: int, db: Session = Depends(getdb)): db_blog = db.query(Blog).filter(Blog.id == blog_id).first() if not db_blog: raise HTTPException(status_code=404, detail='Blog not found') return db_blog @app.get('/user/{user_id}', response_model=schemas.User) def show_user(user_id: int, db: Session = Depends(getdb)): db_user = db.query(User).filter(User.id == user_id).first() if not db_user: raise HTTPException(status_code=404, detail='Blog not found') return db_user
错误原因
delete()返回值类型错误:query.filter(...).delete()返回的是被删除的记录行数(整数),而非Blog模型实例。后续调用db.refresh(db_blog)时,refresh需要传入ORM实例,传入整数必然触发错误。- 参数类型未声明:
blog_id未指定类型,FastAPI默认将其解析为字符串,可能导致与数据库中整数类型的id匹配异常。 - 违反HTTP状态码规范:HTTP 204状态码要求响应体为空,代码中返回字符串不符合该规范。
- 返回内容错误:
Blog.id是模型类的属性,并非具体记录的id,无法正确显示被删除的博客ID。
修复方案
方案1:先查询实例再删除(推荐)
这种方式可以先验证记录是否存在,再执行删除操作:
@app.delete('/blog/{blog_id}', status_code=status.HTTP_204_NO_CONTENT) def destroy(blog_id: int, db: Session = Depends(getdb)): # 查询目标博客 db_blog = db.query(Blog).filter(Blog.id == blog_id).first() if not db_blog: raise HTTPException(status_code=404, detail='Blog not found') # 删除实例并提交 db.delete(db_blog) db.commit() # 204状态码无需返回内容 return
方案2:直接执行删除并检查行数
如果不需要先查询实例,可以通过删除行数判断操作是否成功:
@app.delete('/blog/{blog_id}', status_code=status.HTTP_204_NO_CONTENT) def destroy(blog_id: int, db: Session = Depends(getdb)): deleted_count = db.query(Blog).filter(Blog.id == blog_id).delete(synchronize_session="evaluate") if deleted_count == 0: raise HTTPException(status_code=404, detail='Blog not found') db.commit() return
修复要点总结
- 为
blog_id添加int类型声明,确保参数类型与数据库字段匹配。 - 移除
db.refresh()调用,删除后的实例无需刷新。 - 验证记录是否存在,避免无意义的删除操作并返回友好提示。
- 遵循HTTP 204状态码规范,不返回任何响应内容。
内容的提问来源于stack exchange,提问作者Ashutosh Singh Khadka
相关产品推荐
相关产品推荐

