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

如何在Pydantic父类静态方法中访问子类属性实现通用CRUD?

解决方案

核心思路是把静态方法替换为类方法,类方法的第一个参数cls会自动指向当前调用的子类,可直接访问子类的Meta类属性,完美解决静态方法无法获取子类信息的问题。

完整基类实现

from typing import List, Optional, Type, TypeVar
from uuid import uuid4
from pydantic import BaseModel, Field
from server.database import get_db

# 定义泛型绑定,保证类型提示正确
T = TypeVar('T', bound='BaseDBModel')

class BaseDBModel(BaseModel):
    # 公共字段可以直接定义在基类,不用每个子类重复写
    id: Optional[str] = Field(default_factory=lambda: str(uuid4()))

    def __init_subclass__(cls, **kwargs):
        """子类初始化钩子,强制要求配置集合名,避免漏写报错"""
        super().__init_subclass__(**kwargs)
        if not hasattr(cls, 'Meta') or not hasattr(cls.Meta, 'collection_name'):
            raise NotImplementedError(f"{cls.__name__}必须定义Meta类,且配置collection_name属性")

    @classmethod
    async def all(cls: Type[T]) -> List[T]:
        ret = get_db()[cls.Meta.collection_name].find()
        return [cls(**i) async for i in ret]

    @classmethod
    async def get(cls: Type[T], id: str) -> Optional[T]:
        ret = await get_db()[cls.Meta.collection_name].find_one({'id': id})
        return cls(**ret) if ret else None

    async def save(self):
        await get_db()[self.__class__.Meta.collection_name].insert_one(self.dict())

    async def update(self, **kwargs):
        await get_db()[self.__class__.Meta.collection_name].update_one(
            {'id': self.id},
            {'$set': kwargs},
        )

    async def delete(self):
        """还可以按需扩展其他通用CRUD方法"""
        await get_db()[self.__class__.Meta.collection_name].delete_one({'id': self.id})

子类使用示例

所有业务模型仅需定义业务字段和集合名即可,无需重复编写CRUD逻辑:

class Campaign(BaseDBModel):
    name: str
    class Meta:
        collection_name = 'campaigns'

class Record(BaseDBModel):
    data: str
    user_id: str
    class Meta:
        collection_name = 'records'

class Fragment(BaseDBModel):
    content: str
    campaign_id: str
    class Meta:
        collection_name = 'fragments'

调用示例

# 查询所有Campaign
all_campaigns = await Campaign.all()
# 查询单个Record
record = await Record.get("xxxx-xxxx-xxxx")
# 保存新Fragment
new_frag = Fragment(content="test", campaign_id="xxx")
await new_frag.save()
# 更新Campaign
campaign = await Campaign.get("xxx")
await campaign.update(name="新名称")

内容的提问来源于stack exchange,提问作者Krishna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 21:24:03