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

Django模板嵌套循环实现导航栏下拉菜单遇阻求解决方案

问题解决:Django嵌套QuerySet循环失效与QuerySet序列化问题

核心问题分析

  1. 迭代器耗尽导致循环失效:你用itertools.chain拼接多个Question QuerySet,返回的是一次性迭代器。模板中第一个stage循环遍历questions后,迭代器就被耗尽,后续stage循环时questions没有数据,自然无法显示下拉菜单。
  2. N+1查询性能问题:循环每个Stage都查询一次Question,会触发多次数据库查询,效率极低。
  3. QuerySet序列化失败:Django QuerySet是惰性查询对象,不能直接被JSON序列化,需要先转为可序列化的Python对象(如字典列表)。

方案一:用Django ORM预取关联(推荐)

利用Django的prefetch_related一次性获取所有关联数据,直接在模板中通过反向关联访问,无需单独传递questions。

1. 优化视图代码

from django.shortcuts import render
from .models import Stage

def edit_pages(request, gameid):
    # 预取每个Stage对应的所有Question,避免N+1查询
    stages = Stage.objects.filter(game_id=gameid).prefetch_related('question_set')
    return render(request, "homeSuperuser/edit_pages.html", {'stages': stages})

注:如果你的Question模型中stage字段设置了related_name(比如related_name="questions"),就把prefetch_related('question_set')改成prefetch_related('questions')。

2. 简化模板代码

直接通过stage.question_set.all访问当前Stage的所有Question,无需额外判断:

<body>
    <div class="topnav">
        {% for st in stages %}
            <div class="dropdown">
                <button class="dropbtn">{{ st.stage_name }}</button>
                <div class="dropdown-content">
                    {% for qs in st.question_set.all %}
                        <a href="#">{{ qs.question_name }}</a>
                    {% endfor %}
                </div>
            </div>
        {% endfor %}
    </div>
</body>

方案二:转为JSON用JavaScript渲染

如果必须用前端渲染,需要先将QuerySet转为可序列化的字典列表,再转成JSON传递。

1. 视图中处理数据并序列化

from django.shortcuts import render
from .models import Stage
import json

def edit_pages(request, gameid):
    stages = Stage.objects.filter(game_id=gameid).prefetch_related('question_set')
    # 手动构造可序列化的字典列表
    stage_data = []
    for stage in stages:
        stage_dict = {
            'id': stage.id,
            'stage_name': stage.stage_name,
            'questions': [
                {'id': q.id, 'question_name': q.question_name} 
                for q in stage.question_set.all()
            ]
        }
        stage_data.append(stage_dict)
    # 转成JSON字符串,注意用escapejs避免前端解析错误
    stage_json = json.dumps(stage_data)
    return render(request, "homeSuperuser/edit_pages.html", {'stage_json': stage_json})

2. 前端用JavaScript渲染

<body>
    <div class="topnav"></div>
    <script>
        // 解析JSON数据
        const stageData = JSON.parse('{{ stage_json|escapejs }}');
        const topnav = document.querySelector('.topnav');
        
        // 动态生成下拉菜单
        stageData.forEach(stage => {
            const dropdown = document.createElement('div');
            dropdown.className = 'dropdown';
            dropdown.innerHTML = `
                <button class="dropbtn">${stage.stage_name}</button>
                <div class="dropdown-content">
                    ${stage.questions.map(q => `<a href="#">${q.question_name}</a>`).join('')}
                </div>
            `;
            topnav.appendChild(dropdown);
        });
    </script>
</body>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 18:15:37