You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Django模板中无重复嵌套渲染自引用模型对象

解决Django自引用模型嵌套列表重复问题

问题根源

你现在出现重复项,是因为视图把所有MyNumber对象都传给了模板——那些有父节点的子对象(比如1.1、1.2)既被当成顶级节点渲染,又作为父节点的子项出现,自然会重复。

步骤1:视图只传递顶级节点

修改视图代码,只过滤出没有父节点(即has_bro为null)的对象,确保模板只处理真正的顶级项:

# 视图文件(如views.py)
from django.shortcuts import render
from .models import MyNumber

def number_tree(request):
    # 仅获取无父节点的顶级对象
    top_numbers = MyNumber.objects.filter(has_bro__isnull=True)
    return render(request, 'numbers.html', {'top_numbers': top_numbers})

步骤2:用模板递归渲染嵌套结构

Django模板支持通过include标签实现递归渲染,拆分模板片段来处理层级结构:

  1. 创建模板片段number_node.html,负责渲染单个节点及其子节点:
<!-- templates/number_node.html -->
<li>{{ number.name }}
    {% if number.mynumber_set.all %}
        <ul>
            {% for child in number.mynumber_set.all %}
                {% include 'number_node.html' with number=child %}
            {% endfor %}
        </ul>
    {% endif %}
</li>
  1. 在主模板numbers.html中调用该片段,渲染所有顶级节点:
<!-- templates/numbers.html -->
<ul>
    {% for number in top_numbers %}
        {% include 'number_node.html' with number=number %}
    {% endfor %}
</ul>

优化建议:给自引用外键设置related_name

如果模型还没设置related_name,建议加上,让子对象查询更直观:

# 模型文件(如models.py)
class MyNumber(models.Model):
    name = models.CharField(max_length=50)
    # 添加related_name,便于直接通过children查询子对象
    has_bro = models.ForeignKey(
        'self',
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name='children'
    )

这时模板片段里的number.mynumber_set.all就可以改成number.children.all,可读性更强。

最终渲染出的列表会是无重复的层级结构:

  • 1
    • 1.1
      • 1.1.1
      • 1.1.2
    • 1.2

内容的提问来源于stack exchange,提问作者Firdavsbek Narzullaev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 10:17:19