1

pymongoでcollection.find()、ベースから継承するカスタムカーソルクラスをメソッドに返すことは可能ですか?ただし、反復の発生方法を再定義しますか?

反復時にカーソル内のmongoデータからアプリ固有のモデルをインスタンス化したいと思います。ドキュメントには、type作成するインスタンスの種類を決定する属性があります。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)

これは私が考えることができることですが、イテレータの上に追加の処理をスタックし、変更されたイテレータを返すものなら何でも機能します。

4

2 に答える 2

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 からフェッチされるときに、反復ごとの特別なロジックを実行できます。

于 2012-10-11T19:10:52.037 に答える
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')

andメソッドSerializableを使用して基本クラスを定義しました。これにより、クラスインスタンスを照会して取得できるように を定義することができました。from_dictto_dictto_list()CustomCursor

result: List[School] = database.schools.find().to_list(School)
于 2021-05-12T12:55:39.533 に答える