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)
class Member(models.Model):
name = models.CharField(max_length=100)
active = models.BooleanField()
objects = ActiveManager()
def __unicode__(self):
return self.name
class ActiveManager(models.Manager):
use_for_related_fields = True
def get_query_set(self):
return super(ActiveManager, self).get_query_set().filter(active=True)
因此,我们无法再从菲尔的个人资料中获取他的会员记录:
>>> 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.
简而言之,答案是:在this bug被修复之前,“用于相关字段”在django中不起作用,除了一对一的关系,所以不要担心您的用例是m2m还是m2one,否则您会失望的。
这是一个全球性的环境吗?所以,如果我在一个模型管理器上指定这个属性,所有模型类都会全局使用它吗?
如果我理解您所说的global的意思,那么答案是否定的。它将只用于默认管理器(类中指定的第一个管理器)设置的类。您可以在多个模型中重用管理器,并且该属性只会对其作为默认管理器的那些类产生影响。
这是我认为一个例子有助于理解的东西。允许使用以下以一对一关系链接的成员和配置文件模型:
我们将创建两个成员,活动的John和非活动的Phil,并为每个成员设置一个配置文件:
Django如何存储关系
首先,让我们看看Django是如何存储关系的。我们将获取John的配置文件并查看其名称空间:
在这里,我们可以看到通过存储成员实例的ID值来定义关系。当我们引用
member
属性时,Django使用管理器从数据库检索成员详细信息并创建实例。顺便说一下,如果我们想再次使用此信息,则会缓存此信息:使用哪个管理器
除非另有说明,否则Django使用标准管理器来查找关系,而不是使用添加到模型中的任何自定义管理器。例如,假设我们创建了以下管理器以仅返回活动成员:
然后我们将其作为默认管理器添加到我们的成员模型中(在现实生活中,这是一个坏主意™ 由于许多实用程序(如
dumpdata
管理命令)只使用默认管理器,因此筛选实例的默认管理器可能会导致丢失数据或类似的恶劣副作用):现在管理器过滤掉了不活动的用户,我们只能从数据库中检索John的成员资格:
但是,两个配置文件都可用:
因此,我们可以通过概要文件找到非活动成员,因为关系查找仍然使用标准管理器,而不是自定义管理器:
但是,如果我们现在在管理器上设置
use_for_related_fields
属性,这将告诉Django它必须使用此管理器进行任何关系查找:因此,我们无法再从菲尔的个人资料中获取他的会员记录:
请注意,只有当自定义管理器是模型的默认管理器(即,它是定义的第一个管理器)时,此选项才有效。因此,让我们尝试使用标准管理器作为默认管理器,使用自定义管理器作为辅助管理器:
这两位经理在直视成员时工作如期:
由于默认管理器可以检索所有对象,因此关系查找也会成功:
现实
到目前为止,您现在可以了解为什么我选择一对一的关系作为示例模型。事实证明,实际上(与文档相反),属性
use_for_related_fields
仅用于一对一关系。外键和多对多关系忽略它。这是Django追踪器中的ticket #14891。对于同一个模型,一个模型管理器可以管理一个关系,另一个模型管理器可以管理另一个关系吗?
不。不过,在this discussion of the bug mentioned above中,这是将来的一种可能性。
相关问题 更多 >
编程相关推荐