FastAPI:让VStatus的Create/Update schema自动生成is_verified且不显示于OpenAPI示例
解决方案:分离请求/响应模型+自动计算字段
问题背景
你有一张VStatus表用于跟踪实体验证状态,当前FastAPI的OpenAPI文档中POST请求体包含is_verified字段,但你希望创建/更新记录时仅传入veri_status和vdesc,is_verified由系统自动计算,同时响应结果中包含该字段,但请求体的OpenAPI示例不显示它。
具体实现步骤
1. 重构模型结构,分离请求与响应字段
将核心请求字段(veri_status、vdesc)与包含自动计算字段的数据库/响应模型分离,避免is_verified出现在请求schema中:
from sqlmodel import SQLModel, Field, Column, String, Boolean from uuid import UUID from enum import Enum from sqlalchemy import case class VerificationStatusEnum(Enum): Unverified = "Unverified" Verified = "Verified" Pending = "Pending" # 仅包含请求所需的核心字段,用于Create/Update请求模型 class VStatusCore(SQLModel): veri_status: VerificationStatusEnum = Field( default=VerificationStatusEnum.Unverified, nullable=False) vdesc: str = Field(default='', sa_column=Column("vdesc", String)) # 数据库实体模型,包含自动计算的is_verified class VStatus(VStatusCore, table=True): id: UUID = Field(default=None, primary_key=True) # 数据库层面自动计算is_verified:当veri_status为Verified时设为True,否则False is_verified: bool = Field( sa_column=Column( Boolean, server_default=case( (veri_status == VerificationStatusEnum.Verified, True), else_=False ), server_onupdate=case( (veri_status == VerificationStatusEnum.Verified, True), else_=False ) ) ) # Create请求模型:仅继承核心字段,OpenAPI文档不会显示is_verified class IVStatusCreate(VStatusCore): pass # Read响应模型:包含所有字段(包括自动生成的is_verified) class IVStatusRead(VStatusCore): id: UUID is_verified: bool # 简洁版响应模型 class IVStatusConciseRead(SQLModel): veri_status: VerificationStatusEnum is_verified: bool # Update请求模型:同样仅继承核心字段,更新时自动同步is_verified @optional class IVStatusUpdate(VStatusCore): pass
2. 自动计算is_verified的两种方式
数据库层面自动计算(推荐):
上述代码通过SQLAlchemy的case表达式实现了server_default和server_onupdate逻辑,当插入或更新veri_status时,数据库会自动计算并设置is_verified的值,无需在业务代码中额外处理。业务代码中计算:
如果不想依赖数据库计算逻辑,可以在FastAPI端点中手动计算:from fastapi import FastAPI, Depends, HTTPException from sqlmodel import Session, create_engine app = FastAPI() engine = create_engine("sqlite:///test.db") def get_session(): with Session(engine) as session: yield session @app.post("/vstatus/", response_model=IVStatusRead) def create_vstatus(vstatus_data: IVStatusCreate, session: Session = Depends(get_session)): # 根据veri_status计算is_verified is_verified = vstatus_data.veri_status == VerificationStatusEnum.Verified # 创建数据库实例并传入计算后的值 db_vstatus = VStatus(**vstatus_data.dict(), is_verified=is_verified) session.add(db_vstatus) session.commit() session.refresh(db_vstatus) return db_vstatus @app.patch("/vstatus/{vstatus_id}", response_model=IVStatusRead) def update_vstatus(vstatus_id: UUID, vstatus_data: IVStatusUpdate, session: Session = Depends(get_session)): db_vstatus = session.get(VStatus, vstatus_id) if not db_vstatus: raise HTTPException(status_code=404, detail="VStatus not found") # 更新核心字段 update_data = vstatus_data.dict(exclude_unset=True) for key, value in update_data.items(): setattr(db_vstatus, key, value) # 重新计算is_verified db_vstatus.is_verified = db_vstatus.veri_status == VerificationStatusEnum.Verified session.commit() session.refresh(db_vstatus) return db_vstatus
3. 验证效果
此时,Create和Update的请求体示例将只显示veri_status和vdesc,而响应示例会包含is_verified字段,完全符合需求。
内容的提问来源于stack exchange,提问作者Jim
相关产品推荐
相关产品推荐

