从 pydantic 模型中的父静态方法访问子 class 属性
accessing child class attributes from parent static methods in pydantic models
给定一个花哨的 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},
)
从上面的模型定义可以看出,函数[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
在不同 classes 的所有这些方法中,唯一的变化是 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'
但是,此代码仅适用于实例方法(即 save、update),不适用于 所有和得到。我不确定父 class 静态方法将如何访问 python?
中子项的 Meta class
如对上述方法提出任何建议或改进,我们将不胜感激。
静态方法应该是 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'
(尚不清楚Record
和Fragment
是否应该直接继承自Campaign
或BaseDBModel
。)
给定一个花哨的 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},
)
从上面的模型定义可以看出,函数[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
在不同 classes 的所有这些方法中,唯一的变化是 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'
但是,此代码仅适用于实例方法(即 save、update),不适用于 所有和得到。我不确定父 class 静态方法将如何访问 python?
中子项的 Meta class如对上述方法提出任何建议或改进,我们将不胜感激。
静态方法应该是 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'
(尚不清楚Record
和Fragment
是否应该直接继承自Campaign
或BaseDBModel
。)