Django模板:与外键级联显示对象

时间:2018-09-20 14:38:27

标签: django django-models django-templates

我正在尝试在模板中显示通过Foreign Key field连接的django对象。

我试图举一个简单的例子,以说明我想使用accordion html从模板中得到什么。

我的Django模型:

class Grandparent(models.Model):
    name = models.CharField(...)
    age = models.IntegerField(...)

    def __str__(self):
        return f"{self.name} : {self.age}"


class Parent(models.Model):
    name = models.CharField(...)
    age = models.IntegerField(...)
    grandparent = models.ForeignKey(Grandparent, related_name='grandparent')

    def __str__(self):
        return f"{self.name} : {self.age}"


class Child(models.Model):
    name = models.CharField(...)
    age = models.IntegerField(...)
    parent = models.ForeignKey(Parent, related_name='parent')

    def __str__(self):
        return f"{self.name} : {self.age}"

如您所见,孩子取决于父母,而父母取决于祖父母。

我的html模板:

现在,我想在HTML模板中显示类似的内容:

enter image description here

所以我的HTML如下所示,我并没有克服想要的东西:

{% for grandparent in grandparent_list %}
<div class="accordion-publication panel-group" id="accordion" role="tablist" aria-multiselectable="true">
  <div class="panel-primary">
    <div class="panel-heading" role="button" id="head_0" data-toggle="collapse">
      <span>{{ grandparent }}</span>
    </div>
    {% for parent in parent_list %}
    <div class="panel-collapse collapse in" role="tabpanel" aria-expanded="true">
      <div class="panel-body">
        <div class="panel panel-default">
          <div class="panel-heading collapsed" role="button" data-toggle="collapse" aria-expanded="true">
            <span class="panel-title">{{ parent }}</span>
          </div>
          <div class="panel-collapse collapse in" role="tabpanel" aria-labelledby="head_0">
            <div class="panel-body">
            {% for child in child_list %}
              <table class="table table-condensed">
                <tbody>
                  <tr>
                    <td class="col-md-1"> {{ child }}</td>
                  </tr>
                </tbody>
              </table>
            {% endfor %}
            </div>
          </div>
        </div>
      </div>
    </div>
    {% endfor %}
  </div>
</div>
{% endfor %}

此HTML有点通用,但是为了显示for each grandparent显示each parents associated然后显示each child associated to each parent,我并没有克服获取每个级别和子级别之间的关系的要求。

我的django视图:

我在django视图中的班级是这样的:

def get_context_data(self, **kwargs):

    self.count_number_document()
    self.flag_publication()
    kwargs['child_list'] = Child.objects.all().order_by('parent__grandparent__name')
    kwargs['parent_list'] = Parent.objects.all().order_by('name')
    kwargs['grandparent_list'] = Grandparent.objects.all()

    return super(MyClassView, self).get_context_data(**kwargs)

2 个答案:

答案 0 :(得分:2)

感谢阿拉斯代尔的回答,我找到了解决方法。

首先,我必须这样定义我的模型(related_name调整):

class Grandparent(models.Model):
    name = models.CharField(...)
    age = models.IntegerField(...)

    def __str__(self):
        return f"{self.name} : {self.age}"


class Parent(models.Model):
    name = models.CharField(...)
    age = models.IntegerField(...)
    grandparent = models.ForeignKey(Grandparent, related_name='parents')

    def __str__(self):
        return f"{self.name} : {self.age}"


class Child(models.Model):
    name = models.CharField(...)
    age = models.IntegerField(...)
    parent = models.ForeignKey(Parent, related_name='children')

    def __str__(self):
        return f"{self.name} : {self.age}"

然后,在我的view.py文件中,只需设置:

kwargs['grandparent_list'] = Grandparent.objects.all().order_by('name')

最后在我的html模板中:

{% for grandparent in grandparent_list %}
<div class="accordion-publication panel-group" id="accordion" role="tablist" aria-multiselectable="true">
  <div class="panel-primary">
    <div class="panel-heading" role="button" id="head_0" data-toggle="collapse">
      <span>{{ grandparent }}</span>
    </div>
    {% for parent in grandparent.parents.all %}
    <div class="panel-collapse collapse in" role="tabpanel" aria-expanded="true">
      <div class="panel-body">
        <div class="panel panel-default">
          <div class="panel-heading collapsed" role="button" data-toggle="collapse" aria-expanded="true">
            <span class="panel-title">{{ parent }}</span>
          </div>
          <div class="panel-collapse collapse in" role="tabpanel" aria-labelledby="head_0">
            <div class="panel-body">
            {% for child in parent.children.all %}
              <table class="table table-condensed">
                <tbody>
                  <tr>
                    <td class="col-md-1"> {{ child }}</td>
                  </tr>
                </tbody>
              </table>
            {% endfor %}
            </div>
          </div>
        </div>
      </div>
    </div>
    {% endfor %}
  </div>
</div>
{% endfor %}

答案 1 :(得分:0)

首先,在所有相关名称上使用“ children”,以便grandparent.children.all()会为grand parent的所有子代(例如Parent实例)提供。父类和子类也是如此。

进入视图,仅在上下文中发送祖父母。但是,等等,如果您访问子代及其子代,这将导致N + 1个查询。 因此,在发送祖父母时使用预取。

grandparents = Grandparent.objects.all().prefetch_related(Prefetch('children', queryset=Parent.objects.all().prefetch_related('children')))