0

0

Django模板中按分类优雅展示多项内容

花韻仙語

花韻仙語

发布时间:2025-11-26 11:19:27

|

843人浏览过

|

来源于php中文网

原创

django模板中按分类优雅展示多项内容

本教程详细介绍了如何在Django模板中,利用内置的`regroup`标签,将数据库中具有相同分类的多个项目进行分组展示。通过优化模板渲染逻辑,避免了重复的分类标题,实现了清晰、结构化的数据呈现,尤其适用于菜单、产品列表等场景,提升了用户界面的可读性和美观性。

1. 背景与问题描述

在Web开发中,我们经常需要展示按类别组织的数据,例如餐厅菜单按菜品类别(主食、饮品、小吃)分组,或电商网站产品按品牌、类型分组。一个常见的挑战是,如何在模板中高效且美观地显示这些数据,确保每个类别只出现一次标题,而其下的所有相关项目则整齐排列

考虑以下Django模型结构,用于表示菜品及其所属类别:

models.py

from django.db import models

class gerechten_Categorie(models.Model):
    """
    定义菜品类别模型。
    """
    categorie = models.CharField(max_length=200)

    def __str__(self):
        return self.categorie

class gerecht_info(models.Model):
    """
    定义菜品信息模型,包含对类别的外键引用。
    """
    categorie = models.ForeignKey(gerechten_Categorie, on_delete=models.CASCADE)
    gerecht_name = models.CharField(max_length=200)
    gerecht_description = models.CharField(max_length=500, blank=True, null=True)
    gerecht_price = models.CharField(max_length=50)

    def __str__(self):
        return self.gerecht_name

在视图函数中,我们通常会获取所有菜品数据:

views.py

from django.shortcuts import render
from django.template import loader
from django.http import HttpResponse
from .models import gerecht_info, gerechten_Categorie

def gerechten(request):
    """
    获取所有菜品及其类别信息。
    """
    template = loader.get_template('café/gerechten.html')
    mydata = gerecht_info.objects.all() # 获取所有菜品
    mydata2 = gerechten_Categorie.objects.all() # 获取所有类别 (此处mydata2在本场景中非必需)

    context = {
        'mygerecht': mydata,
        'mycategories': mydata2
    }   
    return HttpResponse(template.render(context, request))

最初,一个常见的模板渲染方式是直接遍历所有菜品,并在每次迭代中显示其类别标题,这会导致相同类别的标题重复出现,影响页面布局和用户体验。

gerechten.html (原始示例)

{% if mygerecht %}
{% for cat in mygerecht %} {# 这里的cat实际上是gerecht_info对象 #}
<div class="flex">
    <div class="menu-head center">
        <h2>{{cat.categorie}}</h2> {# 每次迭代都会显示类别标题 #}
    </div>
    <div class="menu-item">
        <ul class="price">
            <li>{{cat.gerecht_name}}</li>
            <li>€{{cat.gerecht_price}}</li>
        </ul>
        {% if cat.gerecht_description %}
        <p>{{cat.gerecht_description}}</p>
        {% else %}
        <p></p>
        {% endif %}
    </div>
</div>
{% endfor %}
{% else %}
<div class="menu-head center">
<h2>no items avaible</h2>
</div>
{% endif %}

上述代码的问题在于,如果“Hapjes”类别下有三道菜,那么“Hapjes”这个标题会重复出现三次,这并非我们所期望的结构化显示方式。

2. 解决方案:使用Django regroup 模板标签

Django提供了一个强大的内置模板标签regroup,专门用于将列表中的连续相同项进行分组。这正是解决上述问题的理想工具

2.1 regroup 标签介绍

regroup 标签的语法如下:

{% regroup list_to_group by attribute_to_group as new_grouped_list %}
  • list_to_group: 要进行分组的列表(例如,从视图传递过来的mygerecht)。
  • attribute_to_group: 列表中每个对象的属性,根据此属性进行分组(例如,gerecht_info对象的categorie属性)。
  • new_grouped_list: 分组后的新列表的变量名,可以在后续的循环中使用。

new_grouped_list 中的每个元素都是一个对象,包含两个关键属性:

Mokker AI
Mokker AI

AI产品图添加背景

下载
  • grouper: 当前分组的键值(即attribute_to_group的值)。
  • list: 属于当前分组的所有原始对象的列表。

2.2 优化后的模板代码

利用 regroup 标签,我们可以重构 gerechten.html 模板,实现按类别分组显示菜品:

gerechten.html (优化后)

{% comment %}
    在进行分组前,建议对mygerecht列表按类别进行排序,以确保regroup能正确地将所有相同类别的项目连续分组。
    例如:在views.py中 mydata = gerecht_info.objects.all().order_by('categorie__categorie')
{% endcomment %}

{% if mygerecht %}
    {# 使用regroup标签按'categorie'属性对'mygerecht'列表进行分组 #}
    {% regroup mygerecht by categorie as grouped_categories %}

    {% for category_group in grouped_categories %}
    <div class="flex">
        <div class="menu-head center">
            {# 显示当前分组的类别名称 #}
            <h2>{{ category_group.grouper }}</h2> 
        </div>
        {# 遍历当前类别下的所有菜品 #}
        {% for item in category_group.list %}
        <div class="menu-item">
            <ul class="price">
                <li>{{ item.gerecht_name }}</li>
                <li>€{{ item.gerecht_price }}</li>
            </ul>
            {# 显示菜品描述,如果存在 #}
            <p>{% if item.gerecht_description %}{{ item.gerecht_description }}{% endif %}</p>
        </div>
        {% endfor %}
    </div>
    {% endfor %}
{% else %}
<div class="menu-head center">
    <h2>暂无可用菜品</h2>
</div>
{% endif %}

代码解释:

  1. {% regroup mygerecht by categorie as grouped_categories %}: 这行代码是核心。它将mygerecht列表中的所有gerecht_info对象,根据它们的categorie属性(这是一个ForeignKey,regroup会自动访问其__str__方法或pk)进行分组,并将结果存储在grouped_categories变量中。
  2. {% for category_group in grouped_categories %}: 外层循环遍历regroup生成的分组列表。category_group是每个分组的对象。
  3. <h2>{{ category_group.grouper }}</h2>: category_group.grouper会输出当前分组的类别名称(例如,“Hapjes”、“Drankjes”)。
  4. {% for item in category_group.list %}: 内层循环遍历当前类别下的所有菜品。category_group.list是一个包含属于当前类别的gerecht_info对象的列表。
  5. {{ item.gerecht_name }}、{{ item.gerecht_price }}等:在内层循环中,我们可以像往常一样访问每个菜品的详细信息。

通过这种方式,每个类别标题只会显示一次,其下紧跟着该类别的所有菜品,实现了清晰、结构化的展示效果。

3. 注意事项与最佳实践

  1. 数据排序: regroup 标签要求其处理的列表在分组键上是有序的。如果输入列表无序,regroup 会将不连续的相同键视为不同的分组。因此,强烈建议在视图函数中查询数据时,就按照分组依据的字段进行排序。

    # views.py
    def gerechten(request):
        # ...
        # 确保按类别名称排序,以便regroup正确工作
        mydata = gerecht_info.objects.all().order_by('categorie__categorie') 
        # ...

    这里categorie__categorie表示通过外键categorie访问其关联的gerechten_Categorie对象的categorie字段。

  2. 外键属性访问: 当通过外键进行regroup时,如by categorie,Django会自动处理外键关系,通常会使用关联对象的__str__方法作为grouper的值。如果需要使用外键对象的其他属性,例如by categorie.id,则需明确指定。

  3. 性能考虑: regroup是在模板层操作已获取的数据。对于非常大的数据集,如果需要在视图层进行更复杂的聚合或分组,可以考虑在Python代码中使用itertools.groupby或数据库查询的GROUP BY子句(通过annotate等方法)来预处理数据,再传递给模板。然而,对于大多数常规展示需求,regroup已足够高效且方便。

  4. 空列表处理: 在使用regroup前,最好先检查列表是否为空,如示例中的{% if mygerecht %},以避免在空列表上尝试分组导致不必要的渲染。

4. 总结

Django的regroup模板标签是处理按类别或属性分组显示数据的强大工具。它能够显著简化模板逻辑,提高代码可读性,并确保生成结构清晰、用户友好的页面布局。通过遵循数据排序的最佳实践,开发者可以高效地构建动态且美观的数据展示界面。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

WorkBuddy
WorkBuddy

腾讯云推出的AI原生桌面智能体工作台

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Python Web 框架 Django 深度开发
Python Web 框架 Django 深度开发

本专题系统讲解 Python Django 框架的核心功能与进阶开发技巧,包括 Django 项目结构、数据库模型与迁移、视图与模板渲染、表单与认证管理、RESTful API 开发、Django 中间件与缓存优化、部署与性能调优。通过实战案例,帮助学习者掌握 使用 Django 快速构建功能全面的 Web 应用与全栈开发能力。

166

2026.02.04

if什么意思
if什么意思

if的意思是“如果”的条件。它是一个用于引导条件语句的关键词,用于根据特定条件的真假情况来执行不同的代码块。本专题提供if什么意思的相关文章,供大家免费阅读。

847

2023.08.22

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

386

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2111

2023.08.14

vb怎么连接数据库
vb怎么连接数据库

在VB中,连接数据库通常使用ADO(ActiveX 数据对象)或 DAO(Data Access Objects)这两个技术来实现:1、引入ADO库;2、创建ADO连接对象;3、配置连接字符串;4、打开连接;5、执行SQL语句;6、处理查询结果;7、关闭连接即可。

357

2023.08.31

MySQL恢复数据库
MySQL恢复数据库

MySQL恢复数据库的方法有使用物理备份恢复、使用逻辑备份恢复、使用二进制日志恢复和使用数据库复制进行恢复等。本专题为大家提供MySQL数据库相关的文章、下载、课程内容,供大家免费下载体验。

259

2023.09.05

vb中怎么连接access数据库
vb中怎么连接access数据库

vb中连接access数据库的步骤包括引用必要的命名空间、创建连接字符串、创建连接对象、打开连接、执行SQL语句和关闭连接。本专题为大家提供连接access数据库相关的文章、下载、课程内容,供大家免费下载体验。

329

2023.10.09

数据库对象名无效怎么解决
数据库对象名无效怎么解决

数据库对象名无效解决办法:1、检查使用的对象名是否正确,确保没有拼写错误;2、检查数据库中是否已存在具有相同名称的对象,如果是,请更改对象名为一个不同的名称,然后重新创建;3、确保在连接数据库时使用了正确的用户名、密码和数据库名称;4、尝试重启数据库服务,然后再次尝试创建或使用对象;5、尝试更新驱动程序,然后再次尝试创建或使用对象。

420

2023.10.16

Python异步编程与Asyncio高并发应用实践
Python异步编程与Asyncio高并发应用实践

本专题围绕 Python 异步编程模型展开,深入讲解 Asyncio 框架的核心原理与应用实践。内容包括事件循环机制、协程任务调度、异步 IO 处理以及并发任务管理策略。通过构建高并发网络请求与异步数据处理案例,帮助开发者掌握 Python 在高并发场景中的高效开发方法,并提升系统资源利用率与整体运行性能。

37

2026.03.12

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 22.5万人学习

Django 教程
Django 教程

共28课时 | 5万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.9万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号