模板中的 Django for 循环

Django for loop in template

我有两个数据集:

ButikPages = ShopPages.objects.filter(UserID_id=User, Parent_id__isnull=True, IsActive=1, URL=shop_page_slug)
SubPages = ShopPages.objects.filter(UserID_id=User, Parent_id__isnull=False, URL=shop_page_slug)

在我的模板中,我尝试过滤这两个列表,如果一个 ButikPages 查询有子页面,如果不是 link 菜单,它应该是一个下拉菜单。

<ul class="navbar-nav">
    {% for page in ButikPages %}
    {% for parentpage in SubPages %}
    {% if page.IsActive == 1 and parentpage.Parent_id != page.ID %}
       <li class="nav-item"><a class="nav-link" href="/{{ page.Slug }}/">{{ page.PageTitle }}</a></li>
       {% else %}
       <li class="nav-item dropdown">
       <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">{{ page.PageTitle }}</a>
       {% if parentpage.Parent_id == page.ID and parentpage.IsActive == 1 %}
       <ul class="dropdown-menu">
       <li><a class="dropdown-item" href="/{{ parentpage.Slug }}/">{{ parentpage.PageTitle }}</a></li>
       </ul>
      </li>
     {% endif %}
     {% endif %}
     {% endfor %}
     {% endfor %}
      </ul>

如果一个菜单只有一个条目,那是可行的,但如果我有两个子页面,它会出现两次,这是我的理解,因为两个 for 循环。但是如何在没有第二个循环的情况下访问子页面?

PS 如果我只有一种菜单类型会更容易,我知道它可以工作,但唯一的区别是我有两种菜单。

问候。

您似乎在模型 ShopPages 中构建了一个 tree-like object 列表。 我认为你应该先在你的视图中创建tree-like结构,然后在模板中显示它,而不是直接在模板中使用两个for-loop。

类似于:

shop_pages = ShopPages.objects.filter(UserID_id=User, IsActive=1, URL=shop_page_slug)
parents = list(shop_pages.filter(Parent_id__isnull=True).values('pk', 'Parent_id'))
children = list(shop_pages.filter(Parent_id__in=parents).values('pk', 'Parent_id'))
pages = [
    {
        'pk': parent['pk'],
        'parent_id': parent['Parent_id'],
        'sub_pages': [
            {
                'pk': child['pk'],
                'parent_id': child['Parent_id'],
            } for child in children if child['Parent_id'] == parent['pk']
        ],
    } for parent in parents
]

然后在您的模板中执行如下操作:

{% for page in pages %}
    {{ page.pk }}
    ..
    ..
    {% for sub_page in page.sub_pages %}
        {{ sub_page.pk }}
        ..
        ..
    {% endfor %}
{% endfor}

抱歉,我现在无法测试。但是我发现children的位置for循环有一些错误。也许现在可以了。


我突然发现你可以用reverse-FK来收集你的parent-pages的children。所以如果你不改变外键Parent_idrelated_name,它的反向字段就是Parent_id_set,那么你可以这样做:

shop_pages = ShopPages.objects.filter(UserID_id=User, IsActive=1, URL=shop_page_slug)

<ul>
  {% for page in shop_pages %}
  {{ page.pk }}
  ..
    {% for sub_page in page.Parent_id_set.all %}
    {{ sub_page.pk }}
    ..
    {% endfor %}
  {% endfor %}
</ul>

page 的元素移出嵌套循环:

<ul class="navbar-nav">
{% for page in ButikPages %}
    {% if page.IsActive == 1 %}
    <li class="nav-item"><a class="nav-link" href="/{{ page.Slug }}/">{{ page.PageTitle }}</a></li>
    <li class="nav-item dropdown">
        <ul class="dropdown-menu">
        {% for childpage in SubPages %}
            {% if childpage.Parent_id == page.ID %}
            <li><a class="dropdown-item" href="/{{ childpage .Slug }}/">{{ childpage.PageTitle }}</a></li>
            {% endif %}
        {% endfor %}
        </ul>
    </li>
    {% endif %}
{% endfor %}
</ul>

我不太明白你的if条件,可能是我修改的方式不对。

无论如何,@林敬智展示了重构的正确方法——从已经为简单而愚蠢的页面生成准备好的视图中传递数据。避免一遍又一遍地遍历所有子页面。

好的,我找到了解决方案,但我需要一个更简洁的版本:

views.py

def home(request):
    current_site = get_current_site(request)
    try:
        User = MasterData.objects.get(ShopURL=current_site)
        
        SubPages = ShopPages.objects.filter(UserID_id=User, Parent_id__isnull=False)
        parents_id_that_have_childs = ShopPages.objects.filter(Parent_id__isnull=False).values_list('Parent_id', flat=True)
        parents_tmp = ShopPages.objects.filter(ID__in=list(set(parents_id_that_have_childs))).values_list('Slug', flat=True)
        parents = ShopPages.objects.filter(ID__in=list(set(parents_id_that_have_childs)))
        not_parent = ShopPages.objects.filter(UserID_id=User, Parent_id__isnull=True, IsActive=1).exclude(Slug__in=parents_tmp)

查询太多。

模板:

<ul class="navbar-nav">
              {% for page in not_parent %}
               <li class="nav-item"><a class="nav-link" href="{{ page.Slug }}">{{ page.PageTitle }}</a></li>
              {% endfor %}
              {% for parent in parents %}
                    <li class="nav-item dropdown">
                          <a class="nav-link dropdown-toggle" href="#" data-bs-toggle="dropdown">{{ parent.PageTitle }}</a>
                            <ul class="dropdown-menu">
                                {% for parentpage in SubPages %}
                                    {% if parentpage.Parent_id == parent.ID and parentpage.IsActive == 1 %}
                                        <li><a class="dropdown-item" href="/{{ parentpage.Slug }}/">{{ parentpage.PageTitle }}</a></li>
                                    {% endif %}
                                {% endfor %}
                                </ul>
                    </li>
              {% endfor %}
          </ul>