Django如何实现按分类、品牌层级分组展示商品列表
Django 按分类品牌层级展示商品列表解决方案
问题根因
你当前实现直接将全量品牌数据传入模板,遍历逻辑未过滤「当前分类下无对应商品的品牌」,因此会出现空品牌展示的问题,同时模板层嵌套全量遍历加条件判断的写法会产生大量无效运算,查询效率极低。
最优实现方案
方案1:视图层预处理嵌套结构(新手友好,无额外学习成本)
直接在视图层构造好「分类-当前分类下有商品的品牌-对应商品」的三层嵌套结构,模板仅需遍历渲染即可,无需任何条件判断。
views.py 代码
def product_list(request): # 构造三级嵌套结构 category_nested_data = [] for category in Category.objects.all(): # 仅查询当前分类下有商品的品牌,自动去重 related_brands = Brand.objects.filter(product__category=category).distinct() brand_list = [] for brand in related_brands: # 查询当前分类+当前品牌下的所有商品 related_products = Product.objects.filter(category=category, brand=brand) brand_list.append({ "obj": brand, "products": related_products }) category_nested_data.append({ "obj": category, "brands": brand_list }) context = { "category_nested_data": category_nested_data } return render(request, "product/product-list.html", context)
product-list.html 模板代码
<ul> {% for category_item in category_nested_data %} <li>{{ category_item.obj }}</li> <ul> {% for brand_item in category_item.brands %} <li>{{ brand_item.obj }}</li> <ul> {% for product in brand_item.products %} <li>{{ product }}</li> {% endfor %} </ul> {% endfor %} </ul> {% endfor %} </ul>
方案2:ORM 预加载优化版(适合数据量较大的场景)
使用 Django 内置的 Prefetch 预加载关联数据,大幅减少数据库查询次数,提升性能。
views.py 代码
from django.db.models import Prefetch def product_list(request): # 预加载商品关联 product_prefetch = Prefetch( "product_set", queryset=Product.objects.all() ) # 预加载当前分类下有商品的品牌,同时关联对应商品 category_prefetch = Prefetch( "brand_set", queryset=Brand.objects.filter( product__isnull=False ).prefetch_related(product_prefetch).distinct() ) categories = Category.objects.prefetch_related(category_prefetch).all() context = { "categories": categories } return render(request, "product/product-list.html", context)
product-list.html 模板代码
<ul> {% for category in categories %} <li>{{ category }}</li> <ul> {% for brand in category.brand_set.all %} <li>{{ brand }}</li> <ul> {% for product in brand.product_set.all %} {% if product.category == category %} <li>{{ product }}</li> {% endif %} {% endfor %} </ul> {% endfor %} </ul> {% endfor %} </ul>
额外优化提示
你当前的 Category 模型 __str__ 方法返回的是 category_id,如果要和你预期的展示效果对齐显示分类名称,可以把该方法修改为:
def __str__(self): return self.name
内容的提问来源于stack exchange,提问作者SCLH
相关产品推荐
相关产品推荐

