You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 06:28:13