Django模板標簽regroup的妙用
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
屬性 regroup
了 cities
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
模板標簽的用法,從而用於自己的特定需求中,例如像知乎一樣對用戶每天的通知進行分組顯示。
實際應用小例子:
表樣式:
date_article_dict = [
{"year": ‘2019‘, "month": ‘3‘, ‘count‘: 3},
{"year": ‘2019‘, "month": ‘3‘, ‘count‘: 3}
]
效果圖:
代碼:
<h3 class="arch">按月份發文列表</h3> {% regroup date_article_dict by year as year_list %} <ul class="arch"> {% for year in year_list %} <li class=‘yearlist‘ value={{ year.grouper }}> <a href="#" onclick="return false"><span class="headmark"> </span>{{ year.grouper }}年 <span id=‘{{ year.grouper }}‘ class="badge"></span> </a> <ul class=‘{{ year.grouper }} monthlist‘> {% for month in year.list %} <li class="showdatelist" value="{{ year.grouper }}{{ month.month }}"> <a href="javascript:void(0);"> <span class="glyphicon glyphicon-triangle-right"> </span>{{ month.month }}月 <span class="badge">{{ month.m_count }}</span> </a> </li> {% endfor %} </ul> </li> {% endfor %} </ul>
Django模板標簽regroup的妙用