Django 3.2.6二级菜单最优查询方式及模板实现咨询
最优查询方案
你当前的场景是固定两层的级联菜单,完全可以用Django ORM自带的prefetch_related特性实现最优查询,总共仅执行3次SQL,不需要写原生SQL,也不会出现N+1查询问题,性能足够满足绝大多数场景,不需要依赖模板缓存掩盖效率问题。
注意你的模型里用了动态模板生成related_name,格式为你的app名_模型名小写_related,下面代码里的占位符需要替换为你实际的对应值即可:
from django.db.models import Prefetch # 预取二级菜单,过滤已归档数据、按rank排序 level2_prefetch = Prefetch( '替换为你的app名_menuleveltwo_related', queryset=MenuLevelTwo.objects.filter(archived=False).order_by('rank'), to_attr='sorted_level2' ) # 预取一级菜单,同时关联预取二级菜单,过滤已归档数据、按rank排序 level1_prefetch = Prefetch( '替换为你的app名_menulevelone_related', queryset=MenuLevelOne.objects.filter(archived=False).order_by('rank').prefetch_related(level2_prefetch), to_attr='sorted_level1' ) # 最终查询顶级菜单,仅查启用的TOP类型、过滤已归档、按rank排序 menus = Menu.objects.filter( archived=False, type=MenuTypes.TOP.value ).order_by('rank').prefetch_related(level1_prefetch)
模板实现草稿
直接嵌套循环即可渲染出双层菜单结构,示例如下:
<ul class="top-menu"> {% for top_item in menus %} <li> {{ top_item.name }} <ul class="level-1-menu"> {% for level1 in top_item.sorted_level1 %} <li> {{ level1.html|safe }} {% if level1.sorted_level2 %} <ul class="level-2-menu"> {% for level2 in level1.sorted_level2 %} <li>{{ level2.html|safe }}</li> {% endfor %} </ul> {% endif %} </li> {% endfor %} </ul> </li> {% endfor %} </ul>
如果菜单更新频率很低,还可以加模板片段缓存进一步优化性能:
{% load cache %} {% cache 3600 site_main_menu %} <!-- 上面的菜单渲染代码放这里 --> {% endcache %}
其中3600为缓存有效期,单位为秒,可根据业务需求调整。
内容的提问来源于stack exchange,提问作者Trts
相关产品推荐
相关产品推荐

