Django模板标签regroup的妙用

在使用 Django 开发时,有时候我们需要在模板中按对象的某个属性分组显示一系列数据。例如博客文章按照时间归档分组显示文章列表(示例效果请看我的博客的归档页面),或者需要按日期分组显示通知(例如知乎)的通知列表。如果不熟悉 Django 内置的 regroup 模板标签,要完成这个需求可能还得费点功夫,而使用 regroup 则可以轻松完成任务。

regroup 官方文档示例

regroup 可以根据一个类列表对象中元素的某个属性对这些元素进行重新分组。例如有这样一个记录各个国家各个城市信息的列表:

cities = [
    {'name': 'Mumbai', 'population': '19,000,000', 'country': 'India'},
    {'name': 'Calcutta', 'population': '15,000,000', 'country': 'India'},
    {'name': 'New York', 'population': '20,000,000', 'country': 'USA'},
    {'name': 'Chicago', 'population': '7,000,000', 'country': 'USA'},
    {'name': 'Tokyo', 'population': '33,000,000', 'country': 'Japan'},
]

我们想按照国家分组显示各个国家的城市信息,效果就像这样:

  • India
  • Mumbai: 19,000,000
  • Calcutta: 15,000,000
  • USA
  • New York: 20,000,000
  • Chicago: 7,000,000
  • Japan
  • Tokyo: 33,000,000

在模板中使用 regroup 模板标签就可以根据 country 属性对 cities 进行分组:

{% regroup cities by country as country_list %}

<ul>
{% for country in country_list %}
    <li>{{ country.grouper }}
    <ul>
        {% for city in country.list %}
          <li>{{ city.name }}: {{ city.population }}</li>
        {% endfor %}
    </ul>
    </li>
{% endfor %}
</ul>

基本用法为 {% regroup 类列表对象 by 列表中元素的某个属性 as 模板变量 %}

例如示例中根据 cities 列表中元素的 country 属性 regroupcities,并通过 as 将分组后的结果保存到了 country_list 模板变量中。

然后可以循环这个分组后的列表。被循环的元素包含两个属性:

  • grouper,就是分组依据的属性值,例如这里的 ‘India’、‘Japan’
  • list,属于该组下原列表中元素

博客文章按日期归档

官方的例子是分组一个列表,且列表的元素是一个字典。但 regroup 不仅仅限于分组这样的数据结构,只要是一个类列表对象都可以分组,例如一个 QuerySet 对象。举一个博客文章例子,假设博客文章的 Model 定义如下:

from django.db import models

class Post(models.Model):
    title = models.CharField(max_length=100)
    pub_date = models.DatetimeField() # 文章发布时间

现在要按照发布日期的年、月对文章进行分组显示,例如最开始给出的我的个人博客的归档页面示例,可以这样做:

{% regroup post_list by created_time.year as year_post_group %}

<ul>
  {% for year in year_post_group %}
  <li>{{ year.grouper }} 年
    {% regroup year.list by created_time.month as month_post_group %}
    <ul>
      {% for month in month_post_group %}
      <li>{{ month.grouper }} 月
        <ul>
          {% for post in month.list %}
          <li><a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
          </li>
          {% endfor %}
        </ul>
      </li>
      {% endfor %}
    </ul>
  </li>
  {% endfor %}
</ul>

假设模板中有一个包含 Post 列表的变量 post_list,先按照年份对其分组,然后循环显示这些年份,而在某个年份的循环中,又对该年份下的文章按照月份对其分组,然后循环显示该年中各个月份下的文章,这样就达到了一个日期归档的效果。

只要分好组后,就可以任意控制模板显示的内容了,例如你不想循环显示全部文章标题,只想显示各个月份下的文章数量,稍微修改一下模板即可:

{% regroup post_list by created_time.year as year_post_group %}

<ul>
  {% for year in year_post_group %}
  <li>{{ year.grouper }} 年
    {% regroup year.list by created_time.month as month_post_group %}
    <ul>
      {% for month in month_post_group %}
      <li>{{ month.grouper }} 月(month.list | length)</li>
      {% endfor %}
    </ul>
  </li>
  {% endfor %}
</ul>

注意这里使用 length 过滤器而不是使用 month.list.count 方法,因为 month.list 已经是不再是一个 QuerySet 对象。

总结

regroup 模板标签对于需要层级分组显示的对象十分有用。但有一点需要注意,被分组的对象一定要是已经有序排列的,否则 regroup 无法正确地分组。相信从以上两个示例中你可以很容易地总结出 regroup 模板标签的用法,从而用于自己的特定需求中,例如像知乎一样对用户每天的通知进行分组显示。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏difcareer的技术笔记

关于EGL与示例代码[转]

OpenGL ES的javax.microedition.khronos.opengles 包定义了平台无关的GL绘图指令,EGL(javax.microedi...

9030
来自专栏面朝大海春暖花开

jquery实用的一些方法

当你想实现最基本的加减法的时候,对于转换number实用Number(str)即可

9510
来自专栏老马寒门IT

高性能前端 art-template 模板

官网: https://aui.github.io/art-template/zh-cn/index.html

52100
来自专栏前端大白专栏

使用react心得

15950
来自专栏北京马哥教育

python实现简单爬虫功能

iOS开发如果之前没接触过除了c和c++(c++太难了,不花个十来年基本不可能精通)的语言,第二门语言最好的选择就是Python.原因就是 1.语法简单 2.库...

33870
来自专栏逍遥剑客的游戏开发

Nebula3的Input系统

21060
来自专栏为数不多的Android技巧

Android Studio你不知道的快捷键(二)

在Android Studio你不知道的快捷键(一)里面,主要讲述了一些窗口操作的快捷键还有补全参数提示等,这一篇会分享一些代码代码编辑的快捷键。(默认Keym...

12120
来自专栏吴伟祥

Velocity语法大全 转

本文转载自:http://www.cnblogs.com/codingsilence/archive/2011/03/29/2146580.html

7140
来自专栏君赏技术博客

Jekyll-Admin-Mac-列表

接下来我们需要就是做出这个列表数据,我们可以使用 NSTableView来做出这个效果。

16710
来自专栏我的小碗汤

一个神秘现象引发对beego框架的思考

小强最近在项目中遇到了一个很奇怪的问题:在整改日志规范时,为了避免影响现有的代码结构以及改动尽可能小的前提下,在调用记日志的SDK处将某一个字段值首字母改为大写...

8240

扫码关注云+社区

领取腾讯云代金券