如何将Pydantic BaseModel的字段作为Literal类型参数实现通用化?
如何将Pydantic BaseModel的字段作为Literal类型参数实现通用化?
当然可以实现!我之前也遇到过类似的需求,手动硬编码Literal里的字段名实在太繁琐,尤其是模型字段多或者经常变动的时候。下面就给你分享两种通用化的实现方式,既能保留类型检查的优势,又不用每次改模型都同步更新函数的类型提示:
方式一:针对单个模型的简化实现
如果你的更新函数只需要针对特定的DBTable模型,可以先提取出允许更新的字段名,再动态生成Literal类型:
from pydantic import BaseModel from typing import Literal class DBTable(BaseModel): id: int name: str last_name: str # 提取允许更新的字段(排除id) ALLOWED_FIELDS = tuple(k for k in DBTable.__fields__.keys() if k != "id") def set_entry(id: int, key: Literal[ALLOWED_FIELDS], value: str): # 这里写你的数据库更新逻辑 # 比如: # entry = DBTable.get(id) # 假设ORM提供get方法 # setattr(entry, key, value) # entry.save() pass
这样当你给DBTable新增字段(比如email: str),只要在ALLOWED_FIELDS的过滤条件里不排除它,key参数的类型提示会自动包含这个新字段,不用手动修改Literal内容。
方式二:支持任意BaseModel的泛型通用实现
如果需要让函数支持多个不同的BaseModel子类,我们可以用泛型+TypeVar来实现完全通用的版本,同时还能让value的类型自动匹配对应字段的类型(不再固定为str):
from pydantic import BaseModel from typing import TypeVar, Literal, Type # 定义一个绑定到BaseModel的泛型类型 T = TypeVar('T', bound=BaseModel) def set_entry( model_cls: Type[T], id: int, key: Literal[tuple(k for k in T.__fields__.keys() if k != "id")], value: T.__fields__[key].type_ ): # 通用的数据库更新逻辑示例 # entry = model_cls.get(id) # setattr(entry, key, value) # entry.save() pass
使用示例
针对你的DBTable模型调用时:
set_entry(DBTable, 1, "name", "Alice") # 类型检查通过 set_entry(DBTable, 2, "last_name", "Smith") # 类型检查通过 # set_entry(DBTable, 3, "id", 4) # 会触发类型错误,因为id被排除了 # set_entry(DBTable, 3, "name", 123) # 会触发类型错误,因为name字段要求str类型
这种方式的优势在于,不管你后续新增多少个BaseModel子类,这个set_entry函数都能自动适配它们的字段,完全不需要修改函数本身的代码。
备注:内容来源于stack exchange,提问作者Snawe
相关产品推荐
相关产品推荐

