如何从 django 模板访问多对多“通过”表的属性?

Posted

技术标签:

【中文标题】如何从 django 模板访问多对多“通过”表的属性?【英文标题】:How do I access the properties of a many-to-many "through" table from a django template? 【发布时间】:2011-03-23 01:24:22 【问题描述】:

来自 Django 文档...

当您只处理简单的多对多关系(例如混合和匹配比萨饼和浇头)时,您只需要一个标准的 ManyToManyField。但是,有时您可能需要将数据与两个模型之间的关系关联起来。

例如,考虑一个应用程序跟踪音乐家所属的音乐组的情况。一个人与其所属的组之间存在多对多关系,因此您可以使用 ManyToManyField 来表示这种关系。但是,您可能希望收集有关成员资格的很多详细信息,例如此人加入群组的日期。

对于这些情况,Django 允许您指定将用于管理多对多关系的模型。然后,您可以在中间模型上放置额外的字段。中间模型与 ManyToManyField 相关联,使用 through 参数指向将充当中介的模型。对于我们的音乐家示例,代码如下所示:

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)

既然您已经设置了 ManyToManyField 以使用中间模型(在本例中为成员),您就可以开始创建一些多对多关系了。您可以通过创建中间模型的实例来做到这一点:

ringo = Person.objects.create(name="Ringo Starr")
paul = Person.objects.create(name="Paul McCartney")
beatles = Group.objects.create(name="The Beatles")

m1 = Membership(person=ringo, group=beatles,
...     date_joined=date(1962, 8, 16),
...     invite_reason= "Needed a new drummer.")

m1.save()

beatles.members.all()
[<Person: Ringo Starr>]

ringo.group_set.all()
[<Group: The Beatles>]

m2 = Membership.objects.create(person=paul, group=beatles,
...     date_joined=date(1960, 8, 1),
...     invite_reason= "Wanted to form a band.")

beatles.members.all()
[<Person: Ringo Starr>, <Person: Paul McCartney>]

来源:http://docs.djangoproject.com/en/dev/topics/db/models/#intermediary-manytomany

我的问题是,如何设置视图和模板来访问这些附加属性。假设我有一个乐队页面,我想显示乐队名称,遍历会员记录并显示名称和 date_joined。

我应该将带对象传递给模板吗?还是我以某种方式传递成员资格对象?

我将如何在模板中创建 for 循环?

谢谢。

【问题讨论】:

我会考虑稍微缩短 django 文档的摘录。可能会回答的人可能已经熟悉它们,这样更容易发现实际问题。 【参考方案1】:

最简单的方法就是将波段传递给模板。模板能够导航模型之间的关系,并且在 Group 上有 members 和 members_set 查询集管理器。所以我会这样做:

查看:

def group_details(request, group_id):
    group = get_object_or_404(Group, pk=group_id)
    return render_to_response('group_details.html',
                              'group': group)

模板:

<h2> group.name </h2>
% for membership in group.membership_set.all %
    <h3> membership.person </h3>
     membership.date_joined 
% endfor %

【讨论】:

效果很好。我正在尝试遍历 group.membership.all。我需要阅读_set。谢谢! 但是如果您需要更复杂的东西,例如排序、过滤等,标准做法是在视图中完成,然后通过上下文传递? 一个重要的一点是通过表的小写类名使用了“membership”,。【参考方案2】:

我不确定这是否是唯一的解决方案,但将关系对象传递给模板确实有效。在您看来,获取 Membership 对象的 QuerySet:

rel = Membership.objects.filter( group = your_group ).select_related()

并将其传递给模板,您可以在其中使用 % for % 对其进行迭代

% for r in rel %
      r.person.name  joined group  r.group.name  on  r.date_joined <br />
% endfor %

请注意,由于select_related(),这不应执行任何其他查询。

【讨论】:

【参考方案3】:

Rory Hart 的回答大部分是正确的。它允许您在多对多关系中使用中间 (through) 表。

但是,模板中的循环应该按照 cji 的建议使用select_related 进行修改,以避免额外的查询冲击数据库:

<h2> group.name </h2>
% for membership in group.membership_set.select_related %
    <h3> membership.person.name </h3>
     membership.date_joined 
% endfor %

【讨论】:

以上是关于如何从 django 模板访问多对多“通过”表的属性?的主要内容,如果未能解决你的问题,请参考以下文章

多对多模型的 Django 表单。如何从视图/模板填写表格?

如何使用 Django 中的成员资格访问多对多的属性

如何访问 django 模板中的 django ManyToManyField

如何通过模板中的对象访问自定义多对多中的字段

多对多中间表详解 -- Django从入门到精通系列教程

Django:通过另一个多对多关系访问多对多对象