使用 Django 在模板中呈现外键对象
Rendering ForeignKey objects in template with Django
我在呈现模板中的相关对象时遇到问题。我有一个 Page 模型,它与自身有 ForeignKey 关系来定义父子关系。
class Page(BaseModel):
title = models.CharField(
max_length=280,
blank=False,
null=False,
)
description = models.CharField(
max_length=280,
blank=False,
null=False,
)
slug = models.SlugField(
blank=False,
null=False,
)
is_home = models.BooleanField(
default=False,
)
is_parent = models.BooleanField(
default=False,
)
parent = models.ForeignKey(
'self',
on_delete=models.PROTECT,
default='Home',
blank=True,
null=True,
related_name='children',
)
content = RichTextField(
blank=False,
null=False,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('page_detail', args=[str(self.slug)])
我的 views.py 过滤掉非父页面:
class PageListView(ListView):
queryset = Page.objects.filter(is_parent=True, is_home=False)
template_name = 'pages/page_list.html'
context_object_name = 'page'
但是在我的模板中呈现 'child' 对象时,我被卡住了。我想我需要一个循环中的循环(首先用于父页面,第二个用于每个父页面的子页面),但无法使第二个循环工作。这是我最近的尝试,它给我带来了“'Page' 对象不可迭代”错误。
{% extends '_base.html' %}
{% block content %}
<div class="container">
{% for page in page %}
<p>{{ page.title }}</p>
{% for children in page %}
<p>{{ page.title }}</p>
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
您可以迭代 related_name:
构造的管理器
{% block content %}
<div class="container">
{% for page in page %}
<p>{{ page.title }}</p>
{% <b>for child in page.children.all</b> %}
<p>{{ <b>child</b>.title }}</p>
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
您可以使用 .prefetch_related(…)
[Django-doc] 子句提高效率:
class PageListView(ListView):
queryset = Page.objects.filter(
is_parent=True, is_home=False
)<b>.prefetch_related('children')</b>
template_name = 'pages/page_list.html'
context_object_name = 'page'
我还建议不要创建一个额外的字段is_parent
,因为这是一种数据复制。事实证明,保持字段同步,即使在同一个数据库中,也可能比乍看起来更难。您可以检查对象是否是父对象:
class PageListView(ListView):
queryset = Page.objects.filter(
<b>children__isnull=False</b>, is_home=False
).distinct().prefetch_related('children')
template_name = 'pages/page_list.html'
context_object_name = 'page'
我在呈现模板中的相关对象时遇到问题。我有一个 Page 模型,它与自身有 ForeignKey 关系来定义父子关系。
class Page(BaseModel):
title = models.CharField(
max_length=280,
blank=False,
null=False,
)
description = models.CharField(
max_length=280,
blank=False,
null=False,
)
slug = models.SlugField(
blank=False,
null=False,
)
is_home = models.BooleanField(
default=False,
)
is_parent = models.BooleanField(
default=False,
)
parent = models.ForeignKey(
'self',
on_delete=models.PROTECT,
default='Home',
blank=True,
null=True,
related_name='children',
)
content = RichTextField(
blank=False,
null=False,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('page_detail', args=[str(self.slug)])
我的 views.py 过滤掉非父页面:
class PageListView(ListView):
queryset = Page.objects.filter(is_parent=True, is_home=False)
template_name = 'pages/page_list.html'
context_object_name = 'page'
但是在我的模板中呈现 'child' 对象时,我被卡住了。我想我需要一个循环中的循环(首先用于父页面,第二个用于每个父页面的子页面),但无法使第二个循环工作。这是我最近的尝试,它给我带来了“'Page' 对象不可迭代”错误。
{% extends '_base.html' %}
{% block content %}
<div class="container">
{% for page in page %}
<p>{{ page.title }}</p>
{% for children in page %}
<p>{{ page.title }}</p>
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
您可以迭代 related_name:
构造的管理器{% block content %}
<div class="container">
{% for page in page %}
<p>{{ page.title }}</p>
{% <b>for child in page.children.all</b> %}
<p>{{ <b>child</b>.title }}</p>
{% endfor %}
{% endfor %}
</div>
{% endblock content %}
您可以使用 .prefetch_related(…)
[Django-doc] 子句提高效率:
class PageListView(ListView):
queryset = Page.objects.filter(
is_parent=True, is_home=False
)<b>.prefetch_related('children')</b>
template_name = 'pages/page_list.html'
context_object_name = 'page'
我还建议不要创建一个额外的字段is_parent
,因为这是一种数据复制。事实证明,保持字段同步,即使在同一个数据库中,也可能比乍看起来更难。您可以检查对象是否是父对象:
class PageListView(ListView):
queryset = Page.objects.filter(
<b>children__isnull=False</b>, is_home=False
).distinct().prefetch_related('children')
template_name = 'pages/page_list.html'
context_object_name = 'page'