在Django中use_for_related_fields如何工作? [英] How does use_for_related_fields work in Django?

查看:127
本文介绍了在Django中use_for_related_fields如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我无法从文档中掌握这一点。对我而言,这是完全不清楚的:

I'm unable to grasp that from the docs. It's totally unclear to me, more specifically:


  • 是全局设置吗?那么如果我在其中一个模型管理器上指定了这个属性,它将被所有模型类全局使用?

  • 如果它不是一个全局设置,那么这些关系究竟会受到什么影响?

  • 可以为一个关系设置一个模型管理器,另一个可以使用另一个模型管理器,另一个用于与同一模型的另一个关系。

最重要的是,我不会喜欢任何很好的最小化示例用法,因为文档缺少这些afaik。谢谢。

Most of all I would appreciate any good minimal example usages as the documentation lacks those afaik. Thanks.

推荐答案

是全局设置吗?那么如果我在其中一个模型管理器上指定了这个属性,它将被所有模型类全局使用?



如果我已经明白了全球的意思,答案是不。如果默认管理器(类中指定的第一个管理员)已设置,它将仅用于类。您可以在多个模型中重新使用经理,该属性只会对这些类别产生影响。这是默认的经理人。

Is it a global setting? So if I specify this attribute it on one of the model managers, will it be used globally by all the model classes?

If I have understood what you mean by global, the answer is no. It will only be used for a class if the default manager (the first manager specified in the class) has it set. You could re-use the manager in several models, and the attribute would only have an effect on those classes it was the default manager for.

这是我以为例子将有助于理解。让我们使用以一对一关系链接的以下成员和个人资料模型:

This is something I thought an example would help with understanding. Lets use the following member and profile models, linked in a one-to-one relationship:

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)

我们将创建几个成员,即活跃的John和非活动的Phil,并为每个成员设置一个配置文件:

We'll create a couple of members, the active John and the inactive Phil, and set up a profile for each of them:

>>> 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的个人资料,看看它的命名空间:

How Django stores relationships

First, lets look at how Django stores a relationship. We'll take John's profile and look at its namespace:

>>> 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值来定义关系。当我们引用成员属性时,Django使用管理器从数据库中检索成员详细信息并创建实例。顺便说一下,这些信息被缓存,以防我们再次使用它:

Here we can see the relationship is defined by storing the ID value of the member instance. When we reference the member attribute, Django uses a manager to retrieve the member details from the database and create the instance. Incidentally, this information is then cached in case we want to use it again:

>>> 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将使用标准管理器进行此关系查找,而不是添加到模型中的任何自定义管理器。例如,假设我们创建了以下管理器,只返回活动成员:

Which manager to use

Unless told otherwise, Django uses a standard manager for this relationship lookup rather than any custom manager added to the model. For example, say we created the following manager to only return active members:

class ActiveManager(models.Manager):
    def get_query_set(self):
        return super(ActiveManager, self).get_query_set().filter(active=True)

然后我们将其添加到我们的会员模型中作为默认管理器(在现实生活中,这是一个坏主意和交易;作为一些实用程序,如 dumpdata 管理命令,专门使用默认管理器,因此过滤掉实例的默认管理器可能导致丢失的数据或类似的令人讨厌的副作用):

And we then added it to our Member model as the default manager (in real life, this is a Bad Idea™ as a number of utilities, such as the dumpdata management command, exclusively use the default manager, and hence a default manager which filters out instances could lead to lost data or similar nasty side effects):

class Member(models.Model):
    name = models.CharField(max_length=100)
    active = models.BooleanField()

    objects = ActiveManager()

    def __unicode__(self):
        return self.name

现在管理员过滤掉非活动用户,我们只能检索John的Memb来自数据库的人数:

Now that the manager filters out inactive users, we can only retrieve John's membership from the database:

>>> Member.objects.all()
[<Member: John>]

这两个配置文件都可用:

However, both profiles are available:

>>> Profile.objects.all()
[<Profile: 18>, <Profile: 35>]

因此,我们可以通过配置文件访问非活动成员,因为关系查找仍然使用标准管理员,而不是我们的自定义管理员:

And hence we can get to the inactive member through the profile, as the relationship lookup still uses a standard manager rather than our custom one:

>>> p = Profile.objects.get(id=2)
>>> p.member
<Member: Phil>

但是,如果我们现在设置 use_for_related_fields 属性在我们的经理,这将告诉Django它必须使用这个经理任何关系查找:

However, if We now set the use_for_related_fields attribute on our manager, this will tell Django it must use this manager for any relationship lookups:

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的会员资格:

Hence we can no longer get Phil's membership record from his profile:

>>> 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.

请注意,只有自定义管理器是模型的默认管理器(即,它是第一个定义的管理员)。所以,让我们尝试使用标准的管理员作为默认的经理,我们的自定义管理器作为辅助管理员:

Note that this only has an effect if the custom manager is the default manager for the model (i.e., it is the first manager defined). So, lets try using the standard manager as the default manager, and our custom one as a secondary manager:

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

两位经理按照预期的方式工作:直接查看成员:

The two managers work as expected when looking directly at the members:

>>> Member.objects.all()
[<Member: John>, <Member: Phil>]
>>> Member.active_members.all()
[<Member: John>]

默认管理器可以检索所有对象,关系查找也成功:

And since the default manager can retrieve all objects, the relationship lookup succeeds too:

>>> Profile.objects.get(id=2)
>>> p.member
<Member: Phil>



现实



现在,您可以了解为什么我为示例模型选择了一对一的关系。事实证明,在现实中(和文档的矛盾), use_for_related_fields 属性仅用于一对一的关系。外键和多对多关系忽略它。这是Django跟踪器中的门票#14891

The reality

Having made it this far, you now find out why I chose a one-to-one relationship for the example models. It turns out that in reality (and in contradiction of the documentation) the use_for_related_fields attribute is only used for one-to-one relationships. Foreign key and many-to-many relationships ignore it. This is ticket #14891 in the Django tracker.

否。尽管在上述上述错误的这个讨论中,这出现了作为未来的可能性。

No. Although, in this discussion of the bug mentioned above this came up as a possibility in the future.

这篇关于在Django中use_for_related_fields如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆