模板中的 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_id
的related_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>
我有两个数据集:
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_id
的related_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>