FastAPI 中通过 config 配置让 response_model 返回模型外字段

部署运行你感兴趣的模型镜像

FastAPI 中通过 config 配置让 response_model 返回模型外字段

在 FastAPI 中,response_model 的核心作用是校验并格式化响应数据,默认仅返回模型中定义的字段。若业务需要返回模型未声明的额外字段(如动态生成的 trace_idtimestamp 等),可通过模型的 Config 类配置实现,无需修改 response_model 本身。

一、核心配置:extra = Extra.allow

FastAPI 依赖 Pydantic 模型进行数据校验,通过给 Pydantic 模型添加 Config 类,并设置 extra = Extra.allow,即可允许模型接收并返回未在字段中定义的额外数据

1. 基础实现步骤

步骤 1:导入必要模块

需从 pydantic 导入 BaseModel 和 Extra(控制额外字段的处理规则):

from fastapi import FastAPI

from pydantic import BaseModel, Extra  # 导入 Extra 类

from datetime import datetime

import uuid

app = FastAPI()

步骤 2:定义带 Config 的 Pydantic 模型

在模型内部定义 Config 类,设置 extra = Extra.allow,允许额外字段:

# 基础响应模型(仅定义核心字段)

class UserResponse(BaseModel):

    id: int

    name: str

    email: str

    # 关键配置:允许返回模型外的额外字段

    class Config:

        extra = Extra.allow  # 允许额外字段(接收+返回)

步骤 3:接口中返回额外字段

接口逻辑中,返回的数据除了模型定义的 id/name/email,还可添加额外字段(如 trace_idtimestamp),FastAPI 会通过 response_model 正常返回:

@app.get("/user/{user_id}", response_model=UserResponse)

def get_user(user_id: int):

    # 模拟数据库查询的核心数据(匹配模型字段)

    user_core_data = {

        "id": user_id,

        "name": "张三",

        "email": "zhangsan@example.com"

    }

    # 动态添加模型外的额外字段

    extra_data = {

        "trace_id": str(uuid.uuid4()),  # 动态生成的追踪ID

        "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # 时间戳

    }

    # 合并核心数据和额外数据,返回给前端

    return {**user_core_data, **extra_data}

步骤 4:测试接口响应

启动 FastAPI 服务后,访问 http://127.0.0.1:8000/user/1,响应会包含模型字段和额外字段,格式如下:

{

  "id": 1,

  "name": "张三",

  "email": "zhangsan@example.com",

  "trace_id": "a1b2c3d4-5678-90ef-ghij-klmnopqrstuv",  // 模型外字段

  "timestamp": "2025-10-22 15:30:45"  // 模型外字段

}

二、Extra 枚举的其他常用值(根据需求选择)

pydantic.Extra 除了 allow,还有另外两个常用值,需根据业务场景选择,避免误配置导致数据泄露或校验失效:

Extra 值

作用说明

适用场景

Extra.allow

允许模型接收并返回所有额外字段(即 “不拦截” 额外数据)

需要动态返回额外字段的场景

Extra.ignore

忽略额外字段(接收时不报错,但返回时不包含额外字段)

仅需返回模型定义字段的场景

Extra.forbid

禁止额外字段(接收时若有额外字段,直接抛出 ValidationError 异常)

严格校验,不允许任何额外数据

注意:默认情况下,Pydantic 模型的 extra 为 Extra.ignore(即默认不返回额外字段),这也是 “默认无法返回模型外字段” 的根本原因。

三、进阶场景:仅返回部分额外字段(而非全部)

若需更精细的控制(如 “允许接收多个额外字段,但仅返回其中 2 个”),仅靠 extra = Extra.allow 无法满足,可结合以下两种方案:

方案 1:使用 response_model_include 手动指定字段

在接口装饰器中通过 response_model_include 参数,明确指定需要返回的字段(包括模型字段和额外字段):

@app.get(

    "/user/{user_id}",

    response_model=UserResponse,

    # 明确指定返回的字段(包括模型字段 id/name/email 和额外字段 trace_id)

    response_model_include={"id", "name", "email", "trace_id"}

)

def get_user(user_id: int):

    return {

        "id": user_id,

        "name": "张三",

        "email": "zhangsan@example.com",

        "trace_id": str(uuid.uuid4()),  # 会返回

        "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")  # 会被忽略(未在 include 中)

    }

方案 2:动态生成响应模型(适合复杂场景)

若额外字段的数量或名称不固定,可通过 pydantic.create_model 动态生成包含额外字段的临时模型,作为 response_model 使用:

from pydantic import create_model

@app.get("/user/{user_id}")

def get_user(user_id: int):

    # 1. 准备数据(包含核心字段和额外字段)

    response_data = {

        "id": user_id,

        "name": "张三",

        "email": "zhangsan@example.com",

        "trace_id": str(uuid.uuid4()),

        "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),

        "is_active": True  # 新增的额外字段

    }

    # 2. 动态生成响应模型(核心字段+额外字段)

    DynamicUserResponse = create_model(

        "DynamicUserResponse",  # 模型名称(仅用于文档显示)

        __base__=UserResponse,  # 继承基础模型(包含 id/name/email)

        trace_id=(str, ...),    # 额外字段 1(类型+必填)

        timestamp=(str, ...),   # 额外字段 2(类型+必填)

        is_active=(bool, ...)   # 额外字段 3(类型+必填)

    )

    # 3. 返回动态模型校验后的数据

    return DynamicUserResponse(** response_data)

四、注意事项(避免踩坑)

  1. 优先保证模型的 “纯净性”

若额外字段是所有接口的通用字段(如 trace_idcode),建议通过 FastAPI 中间件 统一添加,而非在每个模型中配置 extra = Extra.allow(避免重复代码)。

  1. 避免泄露敏感数据

使用 extra = Extra.allow 时,需确保返回的额外字段中无敏感信息(如用户密码、token 等),必要时通过 response_model_exclude 参数排除敏感字段:

# 排除敏感字段(假设返回数据中包含 password,需排除)

@app.get("/user/{user_id}", response_model=UserResponse, response_model_exclude={"password"})

  1. 文档显示问题

若通过 extra = Extra.allow 返回额外字段,FastAPI 自动生成的接口文档(/docs 或 /redoc)中,响应示例仍会只显示模型定义的字段(不包含额外字段)。若需文档显示额外字段,需手动在模型中添加 example 示例:

class UserResponse(BaseModel):

    id: int

    name: str

    email: str

    class Config:

        extra = Extra.allow

        # 手动添加包含额外字段的示例(文档中会显示)

        schema_extra = {

            "example": {

                "id": 1,

                "name": "张三",

                "email": "zhangsan@example.com",

                "trace_id": "a1b2c3d4-5678-90ef-ghij-klmnopqrstuv",

                "timestamp": "2025-10-22 15:30:45"

            }

        }

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

补充代码: @model_url.post("/updateModel", response_model=None, summary="更新模型接口", tags=["模型管理"]) async def batch_delete_models( req_data: T_DSS_LLMUpdate, session: Session = Depends(get_session), current_user=Depends(UacAuthUtil.get_current_user)): """ 批量删除模型接口 """ try: # 请求体转为字典 req_data = req_data.dict() # 参数 model_id = req_data.get("model_id") model_type = req_data.get("model_type") model_name = req_data.get("model_name") api_key = req_data.get("api_key") endpoint_url = req_data.get("endpoint_url") max_tokens = req_data.get("max_tokens") is_valid = req_data.get("is_valid") if not model_id: return ResponseModel(code=500, message="model_id不可为空") if not is_valid: return ResponseModel(code=500, message="is_valid不可为空") stmt = select(T_DSS_LLM).where(T_DSS_LLM.model_type == model_type, T_DSS_LLM.id==model_id).limit(1) res = await session.exec(stmt) res = res.first() if not res: return ResponseModel(code=500, message="模型不存在!") print("res:", res) encrypted_config = json.loads(res.encrypted_config) # 只更新传入的不为空的字段即可 if model_type: res.model_type = model_type if model_name: res.model_name = model_name if api_key is not None: encrypted_config["api_key"] = ModelService(session).encrypt_api_key(api_key) if endpoint_url: encrypted_config["endpoint_url"] = endpoint_url if max_tokens is not None: encrypted_config["max_tokens"] = max_tokens if is_valid is not None: res.is_valid = is_valid res.encrypted_config=json.dumps(encrypted_config) # 更新模型数据库
最新发布
09-11
以下是补充完整的代码,包括保存更新到数据库返回响应: ```python @model_url.post("/updateModel", response_model=None, summary="更新模型接口", tags=["模型管理"]) async def batch_delete_models( req_data: T_DSS_LLMUpdate, session: Session = Depends(get_session), current_user=Depends(UacAuthUtil.get_current_user)): """ 批量删除模型接口 """ try: # 请求体转为字典 req_data = req_data.dict() # 参数 model_id = req_data.get("model_id") model_type = req_data.get("model_type") model_name = req_data.get("model_name") api_key = req_data.get("api_key") endpoint_url = req_data.get("endpoint_url") max_tokens = req_data.get("max_tokens") is_valid = req_data.get("is_valid") if not model_id: return ResponseModel(code=500, message="model_id不可为空") if not is_valid: return ResponseModel(code=500, message="is_valid不可为空") stmt = select(T_DSS_LLM).where(T_DSS_LLM.model_type == model_type, T_DSS_LLM.id==model_id).limit(1) res = await session.exec(stmt) res = res.first() if not res: return ResponseModel(code=500, message="模型不存在!") print("res:", res) encrypted_config = json.loads(res.encrypted_config) # 只更新传入的不为空的字段即可 if model_type: res.model_type = model_type if model_name: res.model_name = model_name if api_key is not None: encrypted_config["api_key"] = ModelService(session).encrypt_api_key(api_key) if endpoint_url: encrypted_config["endpoint_url"] = endpoint_url if max_tokens is not None: encrypted_config["max_tokens"] = max_tokens if is_valid is not None: res.is_valid = is_valid res.encrypted_config=json.dumps(encrypted_config) # 保存更新到数据库 session.add(res) await session.commit() await session.refresh(res) return ResponseModel(code=200, message="模型更新成功", data=res) except Exception as e: await session.rollback() logger.error(f"更新模型失败: {str(e)}") return ResponseModel(code=500, message=f"更新模型失败: {str(e)}") finally: await session.close() ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值