繁体   English   中英

在 pydantic 模型中从父 static 方法访问子 class 属性

[英]accessing child class attributes from parent static methods in pydantic models

给定一个 pydantic BaseModel class 定义如下:

from typing import List, Optional
from uuid import uuid4

from pydantic import BaseModel, Field
from server.database import get_db


class Campaign(BaseModel):
    id: Optional[str] = Field(default_factory=lambda: str(uuid4()))
    name: str

    @staticmethod
    async def all() -> List:
        ret = get_db()['campaigns'].find()
        return [Campaign(**i) async for i in ret]

    @staticmethod
    async def get(id):
        ret = await get_db()['campaigns'].find_one({'id': id})
        return Campaign(**ret)

    async def save(self):
        await get_db()['campaigns'].insert_one(self.dict())

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

从上面的 model 定义可以看出,函数 [ all , get , save , update ] 可以对多个 CRUD 模型通用,如下所示:

class Record(BaseModel):
    ...
    @staticmethod
    async def all() -> List:
        ret = get_db()['records'].find()
        return [Record(**i) async for i in ret]

    async def save(self):
        pass

class Fragment(BaseModel):
    ...
    @staticmethod
    async def all() -> List:
        ret = get_db()['fragments'].find()
        return [Fragment(**i) async for i in ret]

    async def save(self):
        pass

在不同类的所有这些方法中,唯一的变化是 MongoDB 集合的名称。 现在,我正在为不同的模型多次复制粘贴此代码。

是否有任何通用解决方案,以便我可以将这些方法的定义封装在单个基 class 下,并希望遵循 DRY 原则(而不是现在公然破坏它)。

一种这样的代码配置可以是:

class BaseDBModel(BaseModel):
    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},
        )

class Campaign(BaseDBModel):
    id: Optional[str] = Field(default_factory=lambda: str(uuid4()))
    name: str

    class Meta:
        collection_name = 'campaigns'

但是,此代码仅适用于实例方法(即saveupdate ),不适用于 static 方法,如allget 我不确定父 class staticmethod 将如何访问 python 中子项的Meta class go?

对上述方法的任何建议或改进将不胜感激。

static 方法应该改为 class 方法,以便调用该方法的 class 作为第一个参数传递。 例如,

class BaseDBModel(BaseModel):

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

    @classmethod
    async def get(id):
        ret = await get_db()[cls.Meta.collection_name]({'id': id})
        return class(**ret)

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

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


class Campaign(BaseDBModel):
    id: Optional[str] = Field(default_factory=lambda: str(uuid4()))
    name: str
    
    class Meta:
        collection_name = 'campaigns'


class Record(Campaign):
    class Meta:
        collection_name = 'records'


class Fragment(Campaign):
    class Meta:
        collection_name = 'fragments'

(尚不清楚RecordFragment应该直接继承自Campaign还是BaseDBModel 。)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM