FastAPI中使用Depends时隐藏Pydantic 2字段的问题排查
问题分析
你的代码没有错误,这种差异是FastAPI的预期行为,原因在于它对Body()和Depends()注入的处理逻辑不同:
- 使用
Body()时,FastAPI会直接使用你重写后的模型整体JSON Schema,所以hidden_field会被过滤掉,不会出现在文档中。 - 使用
Depends()时,FastAPI会将模型拆解为独立的字段(默认作为查询参数),逐个提取字段元数据生成文档,这个过程不会触发你重写的__get_pydantic_json_schema__方法,因此hidden_field仍会显示。
解决方法
方案1:公开/内部模型分离(最可靠的常规方案)
创建两个模型,一个面向终端用户(仅包含可见字段),一个面向开发者(包含所有字段),通过依赖函数完成转换:
from pydantic import BaseModel from fastapi import Depends # 面向终端用户的公开模型 class PublicItem(BaseModel): visible_field: str # 面向开发者的内部模型 class Item(BaseModel): visible_field: str hidden_field: str def get_item(public_item: PublicItem = Depends()) -> Item: # 这里可从配置、数据库或其他开发者专属渠道获取hidden_field的值 return Item(visible_field=public_item.visible_field, hidden_field="dev_only_value") @app.get("/test") def test_get(item: Item = Depends(get_item)): return {"item": item}
这种方式下,接口文档只会显示visible_field,同时开发者能拿到完整的Item实例。
方案2:自定义OpenAPI Schema统一过滤字段
通过修改FastAPI生成的OpenAPI Schema,全局移除标记为hidden的字段,同时兼容Body()和Depends()场景:
from fastapi import FastAPI from pydantic import BaseModel, Field from fastapi.openapi.utils import get_openapi app = FastAPI() class Item(BaseModel): visible_field: str hidden_field: str = Field(json_schema_extra={"hidden": True}) def custom_openapi(): if app.openapi_schema: return app.openapi_schema # 生成基础OpenAPI Schema openapi_schema = get_openapi( title="Custom API", version="1.0.0", description="API with hidden fields", routes=app.routes, ) # 过滤所有标记为hidden的字段 for path in openapi_schema["paths"].values(): for operation in path.values(): # 处理请求体中的字段 if "requestBody" in operation: for media_type in operation["requestBody"]["content"].values(): schema = media_type["schema"] if "properties" in schema: schema["properties"] = { k: v for k, v in schema["properties"].items() if not v.get("hidden", False) } # 处理查询参数中的字段 if "parameters" in operation: operation["parameters"] = [ param for param in operation["parameters"] if not param.get("schema", {}).get("hidden", False) ] app.openapi_schema = openapi_schema return openapi_schema # 替换默认的openapi生成逻辑 app.openapi = custom_openapi @app.get("/test") def test_get(item: Item = Depends()): return {"item": item}
内容的提问来源于stack exchange,提问作者khoshahmad
相关产品推荐
相关产品推荐

