使用 Django 在模板中渲染 ForeignKey 对象

Posted

技术标签:

【中文标题】使用 Django 在模板中渲染 ForeignKey 对象【英文标题】:Rendering ForeignKey objects in template with Django 【发布时间】:2020-12-18 10:18:31 【问题描述】:

我无法在模板中呈现相关对象。我有一个 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'

但是在我的模板中渲染“子”对象时,我被卡住了。我认为我需要一个循环内的循环(第一个用于父页面,第二个用于每个父页面的子页面),但无法让第二个循环工作。这是我最近的尝试,它得到了一个“'Page' object is not iterable”错误。

% 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 %

【问题讨论】:

【参考方案1】:

你可以遍历由related_name构造的管理器:

% block content %
<div class="container">
    % for page in page %
        <p> page.title </p>
           % for child in page.children.all %
              <p> child.title </p>
           % endfor %
    % endfor %
</div>
% endblock content %

您可以使用.prefetch_related(…) [Django-doc] 子句提高效率:

class PageListView(ListView):
    queryset = Page.objects.filter(
        is_parent=True, is_home=False
    ).prefetch_related('children')
    template_name = 'pages/page_list.html'
    context_object_name = 'page'

我还建议不要创建一个额外的字段is_parent,因为这是一种数据复制。事实证明,即使在同一个数据库上,保持字段同步也可能比乍看之下更难。您可以检查对象是否为父对象:

class PageListView(ListView):
    queryset = Page.objects.filter(
        children__isnull=False, is_home=False
    ).distinct().prefetch_related('children')
    template_name = 'pages/page_list.html'
    context_object_name = 'page'

【讨论】:

感谢@Willem-van-onsem - 问题已解决!还将听取您的建议,以确保我的查询也有效。

以上是关于使用 Django 在模板中渲染 ForeignKey 对象的主要内容,如果未能解决你的问题,请参考以下文章

使用 Django 在模板中渲染 ForeignKey 对象

如何解析和渲染 json 以在 Django 模板中使用

渲染后如何获取模板(Django)

渲染模板 django cms 插件中的简单循环

在最终渲染之前替换django模板中的char

Django:在部署时通过模板引擎渲染静态文件