pymongo是否有可能让collection.find()
方法返回一个继承自base的自定义游标类,但是重新定义了迭代的发生方式?
我想在迭代时从光标内的mongo数据中实例化特定于app的模型。这些文档有一个type
attr,用于确定应该创建哪种实例。我在想这个next
方法可以查看这个数据并确定要创建和返回的类型。继承光标很容易,但我无法弄清楚将其挂钩到find()
操作的哪个位置?
编辑或者......
我目前正在做的是使用yield
吐出一个生成器,该生成器会在执行提取后对对象进行分类。
@classmethod
def gather(cls,place_id):
"""
Gather instances of all the shouts for one place
"""
shouts = cls.collection.find({'place_id':place_id})
for s in shouts:
yield Shout.classify(s)
@classmethod
def classify(cls,shout):
if shout.type == 1:
return Type1(dict(shout))
elif shout.type == 2:
return Type2(dict(shout))
elif shout.type == 3:
return Type3(dict(shout))
问题是,这不会保留封装在默认pymongo Cursor
中的括号密钥访问的原始方法。
如果我要创建一个只接受游标实例并包装其方法的包装类,我需要覆盖哪些魔术方法来保留原始游标的迭代行为?我在想这样的事情:
class StuffCursor():
cursor = False
def __init__(self,cursor):
self.cursor = cursor
def __getattr__(self,attr):
#This passes off most key-based calls, like bracket-access, to the cursor
return getattr(self.cursor,attr)
这正是我能想到的,但是任何可以在迭代器上堆叠一些额外处理,然后返回修改后的迭代器的东西都可以工作。
答案 0 :(得分:1)
讨厌回答我自己的问题,但这可能对任何人用谷歌搜索都有用。这就是我最终的目标:
class ShoutCursor():
"""
Custom cursor class that will instantiate shout models
at query time.
"""
cursor = False
def __init__(self,cursor):
self.cursor = cursor
self.cursor.sort('created',DESCENDING)
def __iter__(self):
for ent in self.cursor:
yield Shout.classify(ent)
def __len__(self):
return self.cursor.count()
def __getitem__(self,index):
try:
ents = itertools.islice(self.cursor,index,index+1)
return [Shout.classify(ent) for ent in ents][0]
except TypeError:
return list(Shout.classify(ent) for ent in itertools.islice(self.cursor,index.start,index.stop,index.step))
def sort(*args,**kwargs):
self.cursor.sort(*args,**kwargs)
def __getattr__(self,attr):
return getattr(self.cursor,attr)
__iter__
和__getiem__
方法是将已修改的实例化模型加载到生成器中的方法。其他方法保留本机游标操作。将光标传递给__init__
设置功能,因为从mongo获取对象时,可以执行特殊的每次迭代逻辑。
答案 1 :(得分:0)
我不知道是否可以使用“猴子补丁”来实现这一点,但我最终做到了如下所示。这允许我在 Cursor
类上添加/覆盖函数。
from pymongo import MongoClient
from pymongo.collection import Collection
from pymongo.cursor import Cursor
from pymongo.database import Database
class CustomCursor(Cursor):
# Customize Cursor here, either by overriding or extending with more methods
class CustomCollection(Collection):
def __init__(self, database: Database, name: str) -> None:
super().__init__(database, name)
# find_one seems to use find, but you may need to override in more places.
def find(self, *args, **kwargs):
return CustomCursor(self, *args, **kwargs)
class CustomDatabase(Database):
def __init__(self, client: MongoClient, name: str) -> None:
super().__init__(client, name)
def __getitem__(self, name: str) -> CustomCollection:
return CustomCollection(self, name)
# usage:
client = MongoClient('127.0.0.1', 27017)
database = CustomDatabase(client, 'mydb')
我定义了一个 Serializable
基类,带有 from_dict
和 to_dict
方法。这允许我在 to_list()
上定义一个 CustomCursor
,以便我可以查询并获取类实例:
result: List[School] = database.schools.find().to_list(School)