2013-06-03 18 views
5

私が進めているプロジェクトのいくつかの制約のため、DjangoのQuerySetクラスをカスタムクラスに置き換えなければなりませんでした。 QuerySetオブジェクトはメソッドをチェーンにすることができます(例えばQuerySet().filter(...).exclude(...)など)。私の実装では、すべてのメソッドが単にselfを返します。だから私のクラスには、次のようになります。Python - チェーンメソッド: `self`を返すことと新しいクローンオブジェクトを返すこと

class MyQuerySet: 
    ... 
    def filter(self, *args, **kwargs): 
     # Do some stuff and then: 
     return self 

この方法で私は、Djangoのクエリセットの動作を真似しました。しかし

は、Djangoのコードを見て、私の代わりにselfを返す、クエリセットのメソッドは、クローン化されたオブジェクト、それらが呼び出されるたびに返すことに気づきました。

class QuerySet(...): 
    ... 
    def filter(self, *args, **kwargs): 
     clone = self._clone() 
     # Do some stuff and then 
     return clone 

    def _clone(self,...): 
     klass = self.__class__ 
     obj = klass(...) 
     return obj 

だから、基本的には、メソッドが呼び出されるたびに、クエリセットは、自身のクローンを作成し、新しいオブジェクトをインスタンス化し、それを返します。それは、この(削除不要なもの)のように見えます。

私の質問は:なぜですか?私の方法は間違っていますか?
私の恐怖は、私がそれをやっていることです、何かが壊れるかもしれない、そうでなければ私はDjangoチームが何をしたのか説明できません。

+5

は、元のオブジェクトは不変(あなたがクローンではなく、元のオブジェクトを変更している)が保証されていることを意味します。しかし、それは私のところでの見解です。 –

+0

@RobertHarvey - 非常に有効で、ここでの説明を見てください:https://docs.djangoproject.com/en/1.0/ref/models/querysets/#all – karthikr

+1

そのファイルの 'git blame'出力を見ています私は 'self._clone()'がいくつかのコミットから来ているのを見ています。理由が何であれ、この設計はしばらくの間、一貫して実装されました。 https://github.com/django/django/blame/master/django/db/models/query.py – jpaugh

答えて

2

filter()exclude()のような今後の「子」クエリからの変更を継承せずに、基本クエリを保持して再利用できるようにDjangoがこれを行います。私は、後で誰かがクエリを格納しようとしたと思っていて、コピーせずにうまく動作していないことに気づいた。

私はdjangoレポをクローンし、git logdjango/db/models/query.pyに入れて、フレーズcloneを検索しました。

この変更は、ここで紹介したパッチ:クローン化されたオブジェクトを返す

https://github.com/django/django/commit/d4a3a4b

+0

ありがとう@jpaugh!あなたがこのメソッドの最初の使用を釘付けにしたようです。 – user1102018

関連する問題