Djangoでは、モデルクラスがある場合、たとえば.
from Django.db import models
class Transaction(models.Model):
...
次に、モデルにメソッドを追加したい場合は、たとえば適度に複雑なフィルター、カスタムモデルマネージャーを追加できます。
class TransactionManager(models.Manager):
def reasonably_complex_filter(self):
return self.get_query_set().filter(...)
class Transaction(models.Model):
objects = TransactionManager()
そして、私はできる:
>>> Transaction.objects.reasonably_complex_filter()
モデルからクエリセットの最後にチェーンできるカスタムメソッドを追加する方法はありますか?
つまり、私がこれを行うことができるような方法でカスタムメソッドを追加します:
>>> Transaction.objects.filter(...).reasonably_complex_filter()
最終的に最終的になるQuerySet
にメソッドを追加する必要があります。したがって、この機能が必要な場所で定義するメソッドを持つQuerySet
サブクラスを作成して使用する必要があります。
私はそれを行う方法とあなたがしたいかもしれない理由を説明するこのチュートリアルを見つけました:
http://adam.gomaa.us/blog/2009/feb/16/subclassing-Django-querysets/index.html
Django 1.7、機能 クエリセットをマネージャーとして使用する が追加されました:
class PersonQuerySet(models.QuerySet):
def authors(self):
return self.filter(role='A')
def editors(self):
return self.filter(role='E')
class Person(models.Model):
first_name = models.CharField(max_length=50)
last_name = models.CharField(max_length=50)
role = models.CharField(max_length=1, choices=(('A', _('Author')),
('E', _('Editor'))))
people = PersonQuerySet.as_manager()
結果は次のとおりです。
Person.people.authors(last_name='Dahl')
さらに、 カスタムルックアップ を追加する機能も追加されました。
これは、Django 1.3、 Zach Smith とBenの好意により)で機能することが知られている完全なソリューションです。
_class Entry(models.Model):
objects = EntryManager() # don't forget this
is_public = models.BooleanField()
owner = models.ForeignKey(User)
class EntryManager(models.Manager):
'''Use this class to define methods just on Entry.objects.'''
def get_query_set(self):
return EntryQuerySet(self.model)
def __getattr__(self, name, *args):
if name.startswith("_"):
raise AttributeError
return getattr(self.get_query_set(), name, *args)
def get_stats(self):
'''A sample custom Manager method.'''
return { 'public_count': self.get_query_set().public().count() }
class EntryQuerySet(models.query.QuerySet):
'''Use this class to define methods on queryset itself.'''
def public(self):
return self.filter(is_public=True)
def by(self, owner):
return self.filter(owner=owner)
stats = Entry.objects.get_stats()
my_entries = Entry.objects.by(request.user).public()
_
注:get_query_set()
メソッド Django 1.6 で非推奨になりました=;この場合、代わりにget_queryset()
を使用する必要があります。
get_query_set()
メソッドを変更して、必要なメソッドを追加し、カスタムQuerySetを返すことができます。あなたの場合、あなたは以下を使用するでしょう:
_class TransactionManager(models.Manager):
def get_query_set(self):
return TransactionQuerySet(self.model)
class TransactionQuerySet(models.query.QuerySet):
def reasonably_complex_filter(self):
return self.filter(...)
_
TransactionQuerySetをTransaction
モデルまたは関連するManager
にサブクラス化する例を見てきましたが、それは完全にあなた次第です。
編集:objects
が最初にTransactionManager
を参照しているため、実装ではTransaction.objects.reasonably_complex_filter()
が不可能であるという事実を見落としているようです。これは、次の3つの方法で修正できます。
reasonably_complex_filter
_を実装します。Transaction.objects.all().reasonably_complex_filter()
を使用します。QuerySet
とManager
の両方にメソッドを実装するソリューションについては、MarcusWhybrowの回答を参照してください。どのオプションが最も望ましいかはアプリケーションによって異なりますが、コードの重複は強くお勧めします(ただし、グローバルな方法を使用してこれを克服することもできます)。ただし、この種の練習が1回だけ必要な場合、または複雑なフィルターを別のフィルターと組み合わせて使用する場合は、最後のオプションはオーバーヘッドの点でコストがかかりすぎる可能性があります。
カスタムManagerメソッドとカスタムQuerySetメソッドの両方が必要な場合は、from_queryset
を使用できます。
class BaseManager(models.Manager):
def manager_only_method(self):
return
class CustomQuerySet(models.QuerySet):
def manager_and_queryset_method(self):
return
class MyModel(models.Model):
objects = BaseManager.from_queryset(CustomQuerySet)()
https://docs.djangoproject.com/en/2.1/topics/db/managers/#from-queryset
私は実際に別の方法で行くことになった。カスタムメソッドの最後にfilter
呼び出しをチェーンするだけでよいことがわかったので、任意のキーワード引数を取り、それらをfilter()
呼び出しに渡すようにメソッドを修正しました。私のかなり複雑なクエリの終わり:
class TransactionManager(models.Manager):
def reasonably_complex_filter(self, **kwargs):
return self.get_query_set().filter(...).filter(**kwargs)
私の目的には問題なく機能しているようで、QuerySet
をサブクラス化するよりも少し簡単です。