贝利信息

如何在 Django 中高效组织商品与分类的层级展示

日期:2025-12-26 00:00 / 作者:聖光之護

本文讲解如何通过 django 的视图层预处理数据,将商品按分类分组并传递给模板,从而避免在模板中使用非法语法操作变量(如定义列表、条件去重等),实现清晰、可维护的分类商品表格展示。

在 Django 模板中,无法执行赋值操作(如 {% used_category = [] %})或运行复杂逻辑(如动态列表追加、对象比较判断)——这正是你遇到 TemplateSyntaxError: Invalid block tag 的根本原因。Django 模板语言是故意限制逻辑能力的设计,其核心原则是:视图负责数据准备与业务逻辑,模板仅负责展示

✅ 正确做法是:在视图中完成「按分类聚合商品」的工作,并将结构化数据传入模板。

1. 优化模型(推荐添加 related_name)

首先,为 ForeignKey 显式指定 related_name,便于反向查询:

class ShopItem(models.Model):
    itemName = models.CharField(max_length=64)
    price = models.IntegerField()
    category = models.ForeignKey(
        Category,
        on_delete=models.CASCADE,
        related_name='items'  # ← 关键:允许 category.items.all() 获取所有商品
    )

2. 在视图中组织分组数据

使用 prefetch_related 提升性能,并按分类聚合:

# views.py
from django.shortcuts import render
from .models import Category

def shop_items_by_category(request):
    # 获取所有有商品的分类,并预加载其关联商品
    categories = Category.objects.prefetch_related('items').annotate(
        item_count=models.Count('items')
    ).filter(item_count__gt=0).order_by('category')

    return render(request, 'shop/items_by_category.html', {
        'categories': categories
    })
? prefetch_related('items') 会一次性查出所有分类及其商品,避免 N+1 查询;filter(item_count__gt=0) 确保只显示有商品的分类。

3. 模板中简洁渲染(无需逻辑判断!)



  {% for category in categories %}
    
    {% for item in category.items.all %}
      
    {% endfor %}
  {% endfor %}
{{ category.category }}
{{ item.itemName }} {{ item.price }} ¥

⚠️ 注意事项

通过将数据组织逻辑移至视图层,你不仅解决了语法错误,还让代码更符合 Django 的 MVT 架构精神:职责分离、易于测试、便于复用。