web-dev-qa-db-ja.com

Djangoでカスタムマネージャーとカスタムクエリセットのどちらを使用すればよいですか?

Djangoでは、カスタムマネージャーは再利用可能なクエリロジックを整理する優れた方法です。 Custom managers に関するDjangoのドキュメントは次のように述べています:

Managerをカスタマイズする理由は2つあります。追加のManagerメソッドを追加すること、および/または最初のQuerySetを変更すること、Managerが返すことです。

ただし、 説明を続けます カスタムQuerySetクラスを作成する方法、およびこれらはQuerySet.as_manager()を使用して、データモデルからマネージャーとして直接アクセスできるようにすることができます。 :

QuerySet.as_manager()によって作成されたManagerインスタンスは、前の例のPersonManagerと実質的に同一になります。

カスタムManagerおよび/またはカスタムQuerySetクラス間でロジックを整理する方法には、多くの柔軟性があるようです。どちらを使用するかを決定する際の原則は何ですか?

53
John Lehmann

主にクエリを簡単に構成できるようにします。一般に、一連のクエリセット呼び出しの既存のクエリセットに対して何らかの操作を実行したい場合は、QuerySetを使用できます。

たとえば、Imagewidthフィールドを持つheightモデルがあるとします。

class Image(models.Model):
    width = ...  # Width in pixels
    height = ... # Height in pixels

いくつかのカスタムQuerySetメソッドを書くことができます:

class ImageQuerySet(models.QuerySet): 
    def landscapes(self):
        return self.filter(width__gte=models.F('height'))

    def portraits(self):
        return self.filter(width__lte=models.F('height'))

    def small(self):
        return self.filter(width__lte=1200)

    def large(self):
        return self.filter(width__gte=1200)

class ImageManager(models.Manager):
    def get_queryset(self):
        return ImageQuerySet(self.model, using=self._db)

これで、動的なクエリセットを簡単に作成できます。

Image.objects.all().portraits().small()
Image.objects.all().large().portraits()

論理的には、これらの関数は主に、クエリセットのモデルの既存のクエリセットのパーティション化または再定義に関係する必要があります。既存のクエリセットを操作していない状況では、クエリセットをまったく返さないか、この特定のモデルに関係しないいくつかの関連ロジックを、より適切なモデルマネージャよりも実行する必要がある場合があります。

30
Timmy O'Mahony

ManagerQuerySetの違いを自分自身で再学習していたので、ここに書いたほうがいいと思ったので、次回は簡単に書けるようにしました。

Managerは、モデルに接続されているクラスであり、QuerySetインスタンスを返します。objectsはデフォルトのマネージャーです。ほとんどのマネージャーメソッド、例: all()filter()はクエリセットインスタンスを返します。

より詳細には、YourModel.objects.filter(..)を実行すると、クエリセットインスタンスが取得されます。再度フィルタリングする場合は、QuerySetクラスでも使用できるため、別の.filter(..)メソッドをチェーンできます。それはあなたが望むことです..マネージャーとそれが返すクエリセットの両方にあなたのメソッドを持っています。

filterもマネージャーメソッドではなかった場合は、YourModel.objects.all()を実行してクエリセットを取得し、その後そこからfilterメソッドを追加します。

物事を簡単にするために、DjangoはQuerySetクラスのas_manager()メソッドを定義し、それをマネージャーに変換します [docs] =。したがって、クエリセットですべてのカスタムメソッドを定義し、それをマネージャーに変換してモデルにアタッチすることで、最初に(マネージャーメソッドとして)呼び出して、必要なだけチェーンすることができます。 (querysetメソッドとして)。

この回答を書いて、クエリセットメソッドではないDjangoに同梱されているマネージャーメソッドがあるかどうか疑問に思いました。最初に頭に浮かんだのは_get_or_create_メソッドでした。クエリセットは必要ないようですが、何だと思いますか?これもQuerySetクラスで定義されていることがわかりました。

簡単に言えば、ほとんどの場合、QuerySetメソッドを記述し、as_manager()を介してそれらもマネージャーに配置する必要があります。

8
mehmet