在 Django 中创建层次结构视图

Creating a Hierarchy View in Django

我正在尝试在 Django 中创建层次结构视图,但我很难理解如何有效地使用 QuerySets。

我最终的目标是 html 显示如下课程的页面:

Main Course 1 --- Child Course 1
              --- Child Course 2

Main Course 2 --- Child Course 3
              --- Child Course 4

每组课程都将包装在 div 中并设置样式等

在我的 view.py 文件中,我有以下内容:

class HierarchyView(generic.ListView):
template_name = 'curriculum/hierarchy.html'

def get_queryset(self):
    return Offering.objects.all()

def get_context_data(self, **kwargs):
    context = super(HierarchyView, self).get_context_data(**kwargs)
    context['main'] = self.get_queryset().filter(course_type='M')
    context['sub'] = self.get_queryset().filter(parent_code__in=context['main'])
    return context

Offering 模型的设置使得 parent_code 是一个自引用外键(即任何课程都可以是任何其他课程的子课程),如下所示:

...
parent_code = models.ForeignKey(
    'self',
    null=True,
    blank=True,
    on_delete=models.SET_NULL)
...

在我的 html 模板中,我有:

{% for mainoffering in main %}
<div>
<div>{{ mainoffering.course_name }}</div>
  {% for offering in sub %}
  <div>{{ offering.course_name }}</div>
  {% endfor %}
</div>
{% endfor %}

然而,这会导致所有子课程出现在所有主课程下,无论它们是否实际上是该课程的子课程,这显然不是我所追求的。

我仍在学习 Django 的诀窍,我正在努力寻找任何可以用简单的英语解释我需要做什么的东西。请帮忙!

我认为您需要更改模板以使每个子课程与其父课程相匹配。可能是这样的:

{% for mainoffering in main %}
<div>
<div>{{ mainoffering.course_name }}</div>
  {% for offering in sub %}
    {% if offering.parent_code == mainoffering %}
        <div>{{ offering.course_name }}</div>
    {% endif %}
  {% endfor %}
</div>
{% endfor %}

上下文['sub']将return所有这些,没有任何分组、排序等。您可以做几件事来获得所需的行为。

你可以做一个预取相关的。

from django.db.models import Prefetch

offerings = Offering.objects.filter(course_type='M').prefetch_related(
     Prefetch(
         "courses_subset",
         queryset=Offering.objects.filter(parent_code__in=offerings),
         to_attr="sub"
    )
)
for o in offerings:        
    print o.sub

您实际上可以在您的模型中将其作为一个方法并创建一个模板标签(我很可能会使用它)。

method in your Offering model

def get_child_courses(self):
    child_courses = Offerings.objects.filter(parent_code=self.id)
    return child_courses

template tag

@register.simple_tag
def get_child_courses(course):
    return course.get_child_courses()

在您的模板中:

{% for mainoffering in main %}
<div>
<div>{{ mainoffering.course_name }}</div>
  {% for offering in mainoffering|get_child_course %}
  <div>{{ offering.course_name }}</div>
  {% endfor %}
</div>
{% endfor %}

您可以按照 acraze 的建议将它们分组到您的模板中。我个人会选择第二个选项