FastAPI创建用户接口返回UserResponse触发Pydantic验证错误
问题:FastAPI创建用户接口返回时触发Pydantic验证错误
问题背景
使用FastAPI编写的创建用户接口能成功将数据写入数据库,但返回结果时触发Pydantic验证错误,提示first_name、email、created_at字段缺失。
接口代码
@router.post("/", response_model=schemas.UserResponse) def create_user(user: schemas.UserCreate): conn, cursor = get_db() query = """SELECT * FROM users WHERE u_email = %s;""" value = (user.email,) cursor.execute(query, value) row = cursor.fetchone() cursor.close() conn.close() if row is not None: raise HTTPException(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, detail=f"This email already exists") # Create the hash of the user password hashed_password = utils.hash(user.password) user.password = hashed_password # Create the user conn, cursor = get_db() query = """INSERT INTO users (u_fname, u_email, u_password) VALUES (%s, %s, %s) RETURNING *;""" values = (user.first_name, user.email, user.password) cursor.execute(query, values) new_user = cursor.fetchone() conn.commit() cursor.close() conn.close() return new_user
Pydantic模型代码
class UserBase(BaseModel): first_name: constr(min_length=1) email: EmailStr class UserCreate(UserBase): password: str class UserResponse(UserBase): created_at: datetime class Config: orm_mode = True
错误信息
pydantic.error_wrappers.ValidationError: 3 validation errors for UserResponse response -> first_name field required (type=value_error.missing) response -> email field required (type=value_error.missing) response -> created_at field required (type=value_error.missing)
原因分析
核心问题是数据库游标返回的数据格式与Pydantic模型的字段映射不匹配:
- 普通游标执行
fetchone()后返回的是元组,仅包含字段值,没有字段名信息; - Pydantic的
UserResponse模型需要键值对形式的数据(字典或ORM对象)来匹配字段名; - 开启的
orm_mode = True仅适配ORM对象(如SQLAlchemy实例),对普通元组无效,因此模型无法识别元组中的值对应哪个字段,导致字段缺失错误。
解决方法
方案1:使用字典游标
修改get_db()方法,配置游标返回字典格式,让fetchone()直接返回带字段名的键值对:
# 以psycopg2为例,其他数据库驱动语法略有不同 def get_db(): conn = psycopg2.connect( dbname="your_db", user="your_user", password="your_pw", host="your_host" ) # 设置字典游标 cursor = conn.cursor(cursor_factory=psycopg2.extras.DictCursor) try: yield conn, cursor finally: cursor.close() conn.close()
不同数据库驱动的字典游标设置:
- MySQLdb:
cursorclass=MySQLdb.cursors.DictCursor - sqlite3:
cursor = conn.cursor(row_factory=sqlite3.Row)(返回的Row对象可通过键名访问)
方案2:手动映射元组为字典
如果不想修改游标配置,可在获取结果后手动将元组转换为符合模型要求的字典:
new_user = cursor.fetchone() # 需与RETURNING *返回的字段顺序严格对应,示例假设顺序为u_fname, u_email, u_password, created_at new_user_dict = { "first_name": new_user[0], "email": new_user[1], "created_at": new_user[3] } return new_user_dict
内容的提问来源于stack exchange,提问作者José
相关产品推荐
相关产品推荐

