如何在Pydantic序列化时忽略Field中的特定参数?
问题:FastAPI中Filter模型的Field参数序列化错误
需求目标
我希望根据条件筛选书籍,筛选逻辑是将值与数据库列进行比较。于是设计了不同类型的筛选器处理筛选值,再构建Filter模型,通过FastAPI让用户填充筛选器对象并获取筛选结果。
当前可行实现
# filtering.py from pydantic import BaseModel, Field from my_sqlalchemy_models import Book, User class EqualityFilter(BaseModel): value: int _column: Any | None = PrivateAttr(default=None) def __init__(self, **data): super().__init__(**data) self._column = data.get("_column") @property def column(self): return self._column class MinMaxFilter: ... class ContainsFilter: ... class Filter(BaseModel): author_id: EqualityFilter | None = Field(default=None, column=Book.author_id) owner_id: EqualityFilter | None = Field(default=None, column=User.id) owner_name: ContainsFilter | None = Field(default=None, column=User.name) price: MinMaxFilter | None = Field(default=None, column=Book.price) @model_validator(mode="before") @classmethod def add_columns(cls, data: Any): for field_name, value in cls.model_fields.items(): schema_extra = value.json_schema_extra if field_name in data and schema_extra and schema_extra.get("column") is not None: data[field_name]["_column"] = value.json_schema_extra["column"] return data
本地运行时可正常创建筛选器对象:
>>> my_filter = Filter(author_id={"value": 1}, owner_name={"value": "John"}, price={"min": 10}) >>> my_filter.author_id.column <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x105933420>
也能生成SQLAlchemy查询的.where条件:
>>> my_filter.author_id.column == my_filter.author_id.value <sqlalchemy.sql.elements.BinaryExpression object at 0x102bfc860>
遇到的问题
在FastAPI应用中使用Filter模型时,FastAPI生成/docs的openapi.json时无法序列化Field中的column参数,报错:
File "***/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 2250, in json_schema_update_func add_json_schema_extra(json_schema, json_schema_extra) File "***/.venv/lib/python3.12/site-packages/pydantic/_internal/_generate_schema.py", line 2260, in add_json_schema_extra json_schema.update(to_jsonable_python(json_schema_extra)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pydantic_core._pydantic_core.PydanticSerializationError: Unable to serialize unknown type: <class 'sqlalchemy.orm.attributes.InstrumentedAttribute'>
该column参数仅用于内部逻辑,不需要序列化。现需解决:
- 能否在序列化时忽略Field中的特定参数?
- 若当前思路不可行,有哪些替代方案?
最小复现示例
运行以下代码python app.py,访问http://127.0.0.1:8000/docs即可看到错误(示例中将SQLAlchemy模型替换为不可序列化的int,报错信息略有不同但原因一致):
from typing import Any from fastapi import FastAPI from pydantic import BaseModel, Field, PrivateAttr, model_validator class EqualityFilter(BaseModel): value: int _column: Any | None = PrivateAttr(default=None) def __init__(self, **data): super().__init__(**data) self._column = data.get("_column") @property def column(self): return self._column class Filter(BaseModel): author_id: EqualityFilter | None = Field(default=None, column=int) owner_id: EqualityFilter | None = Field(default=None, column=int) @model_validator(mode="before") @classmethod def add_columns(cls, data: Any): for field_name, value in cls.model_fields.items(): schema_extra = value.json_schema_extra if field_name in data and schema_extra and schema_extra.get("column") is not None: data[field_name]["_column"] = value.json_schema_extra["column"] return data app = FastAPI() @app.post("/books") async def get_books(filter: Filter): # do the filtering result = [] return result if __name__ == "__main__": import uvicorn uvicorn.run(app, host="127.0.0.1", port=8000)
内容的提问来源于stack exchange,提问作者sahinakkaya
相关产品推荐
相关产品推荐

