基于单个Model实现网站首页嵌套分类菜单展示求助
Django嵌套分类菜单实现方案
一、模型优化(可选但推荐)
在ProductCategory模型中补充关联名称,方便后续查询子分类,也可添加自定义方法统一子分类排序逻辑:
class ProductCategory(models.Model): name = models.CharField(max_length=50, blank=True, null=True) # 补充related_name,让子分类查询更直观 parent_category = models.ForeignKey( 'self', null=True, blank=True, on_delete=models.CASCADE, related_name='children') category_image = models.ImageField( upload_to='categories/product/imgs/', verbose_name=_("Category Image"), blank=True, null=True, help_text=_("Please use our recommended dimensions: 120px X 120px")) category_description = models.TextField(verbose_name=_("Category Description")) slug = models.SlugField( blank=True, null=True, allow_unicode=True, unique=True, verbose_name=_("Slugfiy")) date = models.DateTimeField(auto_now_add=True, blank=True, null=True) def get_sorted_children(self): # 返回按名称排序的子分类 return self.children.order_by('name')
二、视图层处理
在首页视图中获取所有顶级分类(无父分类的),并通过预加载避免N+1查询问题:
from django.shortcuts import render from .models import ProductCategory from django.db.models import Prefetch def home(request): # 预加载排序后的子分类,减少数据库查询次数 top_categories = ProductCategory.objects.filter(parent_category__isnull=True).prefetch_related( Prefetch('children', queryset=ProductCategory.objects.order_by('name')) ).order_by('name') return render(request, 'home.html', {'top_categories': top_categories})
三、模板递归渲染
1. 首页主模板(home.html)
在首页指定位置引入分类菜单的递归子模板:
<!-- 首页分类菜单区域 --> <div class="category-menu"> <ul class="main-category-list"> {% for category in top_categories %} {% include 'components/category_item.html' with category=category %} {% endfor %} </ul> </div>
2. 递归子模板(components/category_item.html)
创建独立子模板处理单个分类及其嵌套子分类的渲染:
<li class="category-item"> <a href="{% url 'category_detail' category.slug %}" class="category-link"> {% if category.category_image %} <img src="{{ category.category_image.url }}" alt="{{ category.name }}" class="category-icon"> {% endif %} <span>{{ category.name }}</span> </a> <!-- 存在子分类时,递归渲染子菜单 --> {% if category.children.exists %} <ul class="subcategory-list"> {% for subcat in category.children.all %} {% include 'components/category_item.html' with category=subcat %} {% endfor %} </ul> {% endif %} </li>
四、基础样式示例(可选)
添加CSS让嵌套菜单层级更清晰:
.category-menu ul { list-style: none; padding-left: 0; } .main-category-list > .category-item { margin: 10px 0; } .category-link { display: flex; align-items: center; gap: 8px; text-decoration: none; color: #2d3748; padding: 6px 0; } .category-icon { width: 32px; height: 32px; object-fit: cover; border-radius: 4px; } .subcategory-list { padding-left: 24px; margin-top: 4px; border-left: 1px solid #e2e8f0; } .subcategory-list .category-link { font-size: 0.9em; }
五、实用优化点
- 缓存分类数据:分类数据更新频率低,可通过Django缓存框架缓存
top_categories查询结果,减少数据库压力。 - 空值安全处理:模板中对
name、category_image等字段添加空值判断,避免页面渲染报错。 - 排序配置:可在模型中添加
ordering元组,统一分类的默认排序规则。
内容的提问来源于stack exchange,提问作者Devi A
相关产品推荐
相关产品推荐

