給定一個定義如下的 pydantic BaseModel 類:
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
在不同類的所有這些方法中,唯一的變化是 MongoDB 集合的名稱。現在,我正在為不同的模型多次復制粘貼此代碼。
是否有任何通用解決方案,以便我可以將這些方法的定義封裝在單個基類下,并希望遵循 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),不適用于all和get等靜態方法。我不確定父類 staticmethod 將如何訪問python中子類的Meta類?
對上述方法的任何建議或改進將不勝感激。
uj5u.com熱心網友回復:
靜態方法應該是類方法,以便呼叫該方法的類作為第一個引數傳遞。例如,
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直接繼承。)
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/314605.html
下一篇:面向物件編程:子類或列舉
