本文讲解如何通过 django 视图层预处理数据,避免在模板中执行复杂逻辑(如去重、分组),从而安全、高效地实现“按分类聚合商品”的展示需求。
在 Django 中,模板(Template)不是编程环境——它不支持变量赋值(如 {% used_category = [] %})、列表操作或复杂条件判断。你遇到的 TemplateSyntaxError: Invalid block tag 正是因为 Django 模板语言禁止直接声明和修改变量,这与 Python 的语义有本质区别。
✅ 正确做法是:将数据组织逻辑移至 视图(View)层,利用 Django ORM 的能力提前完成分组与关联,再将结构化数据传递给模板。
首先,优化模型(补充 related_name 提升可读性):
class Category(models.Model):
name = models.CharField(max_length=64) # 建议字段名语义更清晰
def __str__(self):
return self.name
class ShopItem(models.Model):
name = models.CharField(max_length=64) # 同上,避免驼峰命名(PEP 8)
price = models.IntegerField()
category = models.ForeignKey(
Category,
on_delete=models.CASCADE,
related_name='items' # 关键!便于反向查询
)
def __str__(self):
return self.
name然后,在视图中组织好“分类 → 商品列表”的嵌套结构:
# views.py
from django.shortcuts import render
from .models import Category
def shop_items_by_category(request):
# 预加载每个分类下的所有商品,避免 N+1 查询
categories = Category.objects.prefetch_related('items').all()
# 可选:只取有商品的分类(更高效)
# categories = Category.objects.filter(items__isnull=False).distinct().prefetch_related('items')
return render(request, 'shop/shop_list.html', {
'categories': categories
})| {{ category.name }} | ||
|---|---|---|
| {{ item.name }} | ${{ item.price }} | |
from django.db.models import Prefetch
categories = Category.objects.prefetch_related(
Prefetch('items', queryset=ShopItem.objects.order_by('-price'))
).all()通过将数据组织逻辑交由视图和 ORM 完成,你不仅解决了模板语法错误,还显著提升了性能、可维护性与代码可测试性——这才是 Django MVT 架构的正确打开方式。