それはグローバルな設定ですか?したがって、この属性をモデルマネージャーの1つで指定すると、すべてのモデルクラスでグローバルに使用されますか?
あなたがグローバルとはどういう意味かを私が理解していれば、答えはノーです。デフォルトのマネージャー(クラスで指定された最初のマネージャー)に設定されている場合にのみ、クラスに使用されます。いくつかのモデルでマネージャーを再利用できます。属性は、デフォルトのマネージャーであったクラスにのみ影響します。
これは、例が理解に役立つと私が思ったものです。1対1の関係でリンクされた、次のメンバーモデルとプロファイルモデルを使用してみましょう。
from django.db import models
class Member(models.Model):
name = models.CharField(max_length=100)
active = models.BooleanField()
def __unicode__(self):
return self.name
class Profile(models.Model):
member = models.OneToOneField(Member)
age = models.PositiveIntegerField()
def __unicode__(self):
return str(self.age)
アクティブなジョンと非アクティブなフィルの2人のメンバーを作成し、それぞれのプロファイルを設定します。
>>> m1 = Member(name='John', active=True)
>>> m1.save()
>>> p1 = Profile(member=m1, age=18)
>>> p1.save()
>>> m2 = Member(name='Phil', active=False)
>>> m2.save()
>>> p2 = Profile(member=m2, age=35)
>>> p2.save()
Djangoが関係を保存する方法
まず、Djangoがどのように関係を保存するかを見てみましょう。Johnのプロファイルを取得し、その名前空間を確認します。
>>> p = Profile.objects.get(id=1)
>>> p.__dict__
{'age': 18, '_state': <django.db.models.base.ModelState object at 0x95d054c>, 'id': 1, 'member_id': 1}
ここでは、メンバーインスタンスのID値を格納することによって関係が定義されていることがわかります。属性を参照するときmember
、Djangoはマネージャーを使用してデータベースからメンバーの詳細を取得し、インスタンスを作成します。ちなみに、この情報は、再度使用する場合に備えてキャッシュされます。
>>> p.member
<Member: John>
>>> p.__dict__
{'age': 18, '_member_cache': <Member: John>, '_state': <django.db.models.base.ModelState object at 0x95d054c>, 'id': 1, 'member_id': 1}
どのマネージャーを使用するか
特に明記されていない限り、Djangoは、モデルに追加されたカスタムマネージャーではなく、この関係ルックアップに標準マネージャーを使用します。たとえば、アクティブなメンバーのみを返すように次のマネージャーを作成したとします。
class ActiveManager(models.Manager):
def get_query_set(self):
return super(ActiveManager, self).get_query_set().filter(active=True)
次に、それをデフォルトマネージャーとしてメンバーモデルに追加しました(実際には、管理コマンドなどの多くのユーティリティがデフォルトマネージャーのみを使用するため、これはBadIdea™でdumpdata
あり、したがって、フィルターで除外されるデフォルトマネージャーです。インスタンスは、データの損失または同様の厄介な副作用につながる可能性があります):
class Member(models.Model):
name = models.CharField(max_length=100)
active = models.BooleanField()
objects = ActiveManager()
def __unicode__(self):
return self.name
マネージャが非アクティブなユーザーを除外するようになったため、データベースからJohnのメンバーシップのみを取得できます。
>>> Member.objects.all()
[<Member: John>]
ただし、両方のプロファイルを使用できます。
>>> Profile.objects.all()
[<Profile: 18>, <Profile: 35>]
したがって、リレーションシップルックアップはカスタムマネージャーではなく標準マネージャーを使用するため、プロファイルを介して非アクティブなメンバーにアクセスできます。
>>> p = Profile.objects.get(id=2)
>>> p.member
<Member: Phil>
ただし、use_for_related_fields
マネージャーに属性を設定すると、関係のルックアップにこのマネージャーを使用する必要があることがDjangoに通知されます。
class ActiveManager(models.Manager):
use_for_related_fields = True
def get_query_set(self):
return super(ActiveManager, self).get_query_set().filter(active=True)
したがって、Philのプロファイルからメンバーシップレコードを取得することはできなくなります。
>>> p = Profile.objects.get(id=2)
>>> p.member
---------------------------------------------------------------------------
DoesNotExist Traceback (most recent call last)
/home/blair/<ipython console> in <module>()
/usr/lib/pymodules/python2.6/django/db/models/fields/related.pyc in __get__(self, instance, instance_type)
298 db = router.db_for_read(self.field.rel.to, instance=instance)
299 if getattr(rel_mgr, 'use_for_related_fields', False):
--> 300 rel_obj = rel_mgr.using(db).get(**params)
301 else:
302 rel_obj = QuerySet(self.field.rel.to).using(db).get(**params)
/usr/lib/pymodules/python2.6/django/db/models/query.pyc in get(self, *args, **kwargs)
339 if not num:
340 raise self.model.DoesNotExist("%s matching query does not exist."
--> 341 % self.model._meta.object_name)
342 raise self.model.MultipleObjectsReturned("get() returned more than one %s -- it returned %s! Lookup parameters were %s"
343 % (self.model._meta.object_name, num, kwargs))
DoesNotExist: Member matching query does not exist.
これは、カスタムマネージャーがモデルのデフォルトマネージャーである場合(つまり、最初に定義されたマネージャーである場合)にのみ効果があることに注意してください。それでは、標準マネージャーをデフォルトマネージャーとして使用し、カスタムマネージャーをセカンダリマネージャーとして使用してみましょう。
class Member(models.Model):
name = models.CharField(max_length=100)
active = models.BooleanField()
objects = models.Manager()
active_members = ActiveManager()
def __unicode__(self):
return self.name
2人のマネージャーは、メンバーを直接見ると期待どおりに機能します。
>>> Member.objects.all()
[<Member: John>, <Member: Phil>]
>>> Member.active_members.all()
[<Member: John>]
また、デフォルトのマネージャーはすべてのオブジェクトを取得できるため、リレーションシップルックアップも成功します。
>>> Profile.objects.get(id=2)
>>> p.member
<Member: Phil>
現実
これまでのところ、サンプルモデルに1対1の関係を選択した理由がわかります。実際には(そしてドキュメントと矛盾して)、use_for_related_fields
属性は1対1の関係にのみ使用されることがわかりました。外部キーと多対多の関係はそれを無視します。これはDjangoトラッカーのチケット#14891です。
同じモデルのある関係に1つのモデルマネージャーを配置し、別の関係に別のモデルマネージャーを配置することは可能ですか?
いいえ。ただし、上記のバグについてのこの議論では、これは将来の可能性として浮かび上がってきました。