Django 中间模型中的访问字段

Posted

技术标签:

【中文标题】Django 中间模型中的访问字段【英文标题】:Access fields in Django intermediate model 【发布时间】:2011-01-01 15:12:48 【问题描述】:

我正在为中间模型创建 Django 文档中所述的人员组和成员资格。

class Person(models.Model):
  name = models.CharField(max_length=128)

  def __unicode__(self):
    return self.name

class Group(models.Model):
  name = models.CharField(max_length=128)
  members = models.ManyToManyField(Person, through='Membership')

  def __unicode__(self):
    return self.name

class Membership(models.Model):
  person = models.ForeignKey(Person)
  group = models.ForeignKey(Group)
  date_joined = models.DateField()
  invite_reason = models.CharField(max_length=64)

可以通过以下方式从 Group 对象访问 Person:

>>>Group.members.name

Django 是否创建另一个查询来获取 Person? 我可以从 Group 对象访问date_joined 字段吗?

让我感到困惑的是,我希望得到 Person name 字段:

>>>Group.members.person.name

如果 Person 有一个字段“name”并且中间模型也有一个字段“name”会发生什么。

【问题讨论】:

【参考方案1】:

您的示例中的 members 字段是 ManyToManyField,因此它是一种访问多人而不是一个人的方式。 members 字段下的对象实际上是一种特殊类型的 Manager,而不是 Person:

>>> print my_group.members
<django.db.models.fields.related.ManyRelatedManager object at 0x181f7d0>

要更好地了解经理是什么,see the documentation。

要访问一个人的名字,你可以这样做:

>>> for person in my_group.members.all():
>>>     print person.name

您无法通过成员字段中的经理访问您的会员模型中的字段。要访问其中的任何字段,您可以:

>>> for membership in my_group.membership_set.all():
>>>     print membership.date_joined

因此,如果您的 Membership 模型中有一个名为 name 的字段,您可以像这样访问它:

>>> for membership in my_group.membership_set.all():
>>>     print membership.name

访问人名的第二种方法是:

>>> for membership in my_group.membership_set.all():
>>>     print membership.person.name

请注意,membership_set 是指向成员的经理的默认名称,但可以通过在相应的外键中指定 related_name 来更改它。例如,如果从 MembershipGroup 的外键定义如下:

    group = models.ForeignKey(Group, related_name="group_members")

然后您将使用group_members 访问管理器:

>>> for membership in my_group.group_members.all():
>>>     print membership.name

希望能有所帮助:)

【讨论】:

您所说的非常有道理,并且符合我对 django 模型的理解。让我感到困惑的是在docs.djangoproject.com/en/1.0/topics/db/models/… 上关于 intemedaite 模型的 django 文档,他们用上面相同的模型展示了这个例子: # 查找名称以 'Paul' 开头的成员的所有组 >>> Group.objects.filter(members__name__startswith=' Paul') [] 我希望它是:>>> Group.objects.filter(members__person__name__startswith='Paul') 它是“Group.objects.filter(members__name__startswith='Paul')”,因为 members 是经理。您必须确保您了解 members 不是 Membership 对象,而是 ManyRelatedManager 对象。我认为,如果您详细了解经理到底是什么,它可能会对您有所帮助。附言如果您在具有这些模型的项目中键入“python manage.py shell”,您可以尝试输入“Group.objects.filter(members__person__name__startswith='Paul')”,看看会发生什么 - 也许这会对您有所帮助?跨度> 我了解会员是经理,我阅读了有关经理的信息。我不明白成员如何决定使用 Person 而不是 Group 的名称。两者都有这个领域。成员资格也可能有一个字段名称。我会过滤这个吗? 每个经理都处理特定类型的对象。 members 字段中的 Manager 处理 Person 对象而不是 Membership 对象。我只访问了中间表中的数据(如何做到这一点在答案中),到目前为止我从来不需要过滤它。但我建议你自己在 python shell 中尝试一下(“manage.py shell”命令)。我认为您可以使用“Group.objects.filter(membership__date_joined='1962-02-12')”。如果 Membership 有一个名称字段,那么“Group.objects.filter(membership__name='abc')”而不是“Group.objects.filter(members__name='Paul')”。 对于人名 "Group.objects.filter(membership__person__name='Paul')" 可能也可以。但我不确定——我建议你自己尝试一下 :) 大多数情况下,Django 的错误消息非常有用。我只是偶尔被他们难倒。【参考方案2】:

使用会员等级的经理:

MyGroup.membership_set.all()

代替:

MyGroup.members.all()

【讨论】:

以上是关于Django 中间模型中的访问字段的主要内容,如果未能解决你的问题,请参考以下文章

如何通过 django 中的父表访问中间表字段?

从与模板中的 django 用户关联的模型中访问字段

Django 访问不属于表单的字段

django模型系统--多对多,一对一以及跨表查询

在我更改了一些模型字段(Django)之后,尝试访问 django admin 时出现 /admin/myapp/mymodel 的 TypeError

访问中间件值以测试Django DetailView