template标签_Django实战: 利用自定义模板标签实现仿CSDN博客月度归档
應網友慕之巖的請求,現提供下Django項目中如何使用自定義標簽實現仿CSDN博客的月度歸檔(如下圖所示)。要求按月統計每個月發表的博文篇數, 跳過空白月份,最后結果按發布時間逆序排列。點擊每個月份可以看到詳細博文列表清單。本文著重講述如何實現,不包括樣式美化。如代碼手機上看不全,可以搜索知乎大江狗或csdn大江狗。
實現原理
假如我們有如下一個Article模型(完整的見Django實戰專題: 開發專業博客(1)之內容管理后臺開發),里面包含了status和發布日期pub_date兩個關鍵字段。
class Article(models.Model):"""文章模型"""STATUS_CHOICES = ( ('d', '草稿'),('p', '發表'),) title = models.CharField('標題', max_length=200, db_index=True) slug = models.SlugField('slug', max_length=60, blank=True) body = RichTextUploadingField('正文') pub_date = models.DateTimeField('發布時間', null=True) create_date = models.DateTimeField('創建時間', auto_now_add=True) mod_date = models.DateTimeField('修改時間', auto_now=True) status = models.CharField('文章狀態', max_length=1, choices=STATUS_CHOICES, default='p')我們實現原理如下:
我們需要構建一個由年份、月份和和當月發表文章數量組成的字典列表。新的列表由如{'year': 2019, 'month': 8, total:'4'}這樣的多個字典組成。
我們先獲取所有已發表文章的最大年份和最小年份,縮小歸檔時間范圍。
利用for循環查詢最大年份和最小年份間每年的12個月中是否有文章發表(逆序查找),如果有,我們將統計該月發表文章的數量,并將由年份、月份和和文章數量構建成的字典插入列表。如果當月無文章發表,我們直接跳過。
最后我們在模板中循環輸出每條記錄的year, month和total即可。同時我們還需要為每條記錄建個url,用于展示對應year和month的月度文章詳細列表。
自定義模板標簽
我們將自定義一個{% show_monthly_archive %}的標簽,用于顯示月度歸檔。這樣做的好處是顯而易見的,因為如果你將來想在不同頁面比如文章詳情、文章列表或搜索頁面顯示月度歸檔信息時,你只需要在相應頁面模板加入這么一行代碼就可以了,而不需要更改視圖增加新的context,也不需要對模板進行大的調整。
更多關于自定義模板標簽的內容見Django基礎(16): 模板標簽(tags)的分類及如何自定義模板標簽。本文只做簡要介紹。首先你要在你的app目錄下新建一個叫templatetags的文件夾(不能取其它名字), 里面必需包含__init__.py的空文件。在該目錄下你還要新建一個python文件專門存放你自定義的模板標簽函數,本例中為blog_extras.py,當然你也可以取其它名字。整個目錄結構如下所示:
blog/? __init__.py
? models.py
? templatetags/
? ? ? __init__.py
? ? ? blog_extras.py
? views.py
在模板中使用自定義的模板標簽時,需要先使用{% load blog_extras %}載入自定義的過濾器,然后通過{% show_monthly_archive %}?使用它。
在blog_extras.py中添加如下代碼。該自定義標簽的作用創建字典列表, ?并通過包含的模板_monthly_archive_list.html循環輸出列表結果。因為這個模板并不是用于顯示整個頁面的主模板,而只是些模板片段,所以我們在它前面加了下劃線_。
#blog_extras.py
from django import templatefrom ..models import Articleregister = template.Library()# show rendered template@register.inclusion_tag('blog/_monthly_archive_list.html')def show_monthly_archive():#按日期逆序排序articles = Article.objects.filter(status='p').order_by('-pub_date')#獲取最大和最小年份max_year = articles[0].pub_date.year min_year = articles[len(articles)-1].pub_date.year#按年和月循環,排除空月份,生成子一個字典列表rows = []for year in range(max_year, min_year -1, -1):for month in range(12, 0, -1): total = Article.objects.filter(pub_date__year=year,pub_date__month=month).count()if total > 0: rows.append({"year": year, "month": month, "total": total, })else:continue return {'rows': rows, }模板blog/_monthly_archive_list.html代碼如下:
歸檔{% for row in rows %}href="{% url 'blog:month_archive' row.year row.month %}">{{ row.year }}年{{ row.month }}月 {{ row.total }}篇{% endfor %}視圖views.py和urls.py
事情還沒結束。我們還需要自定義一個名為month_archive的視圖及其對應urls來根據年份year和月份month來顯示文章清單。注意這里的month_archive.html是主模板哦,我們還加入了分頁。
#urls.py
path('articles///', views.month_archive, name='month_archive'),#views.py
def month_archive(request, year, month): articles = Article.objects.filter(status='p', pub_date__year=year,pub_date__month=month).order_by('-pub_date') paginator = Paginator(articles, 3) page = request.GET.get('page') page_obj = paginator.get_page(page) context = {'page_obj': page_obj, 'paginator': paginator, 'is_paginated': True}return render(request, 'blog/month_archive.html', context)#blog/month_archive.html
{% extends "blog/base.html" %}{% block content %}月度歸檔{# 注釋: page_obj不要改。Article可以改成自己對象 #}{% if page_obj %}class="table table-striped">標題發布日期查看{% for article in page_obj %}{{ article.title }}{{ article.pub_date | date:"Y-m-d" }} href="{% url 'blog:article_detail' article.id article.slug %}">class="glyphicon glyphicon-eye-open">
{% endfor %}{% else %}{# 注釋: 這里可以換成自己的對象 #}沒有文章。{% endif %}{# 注釋: 下面代碼一點也不要動, #}{% if is_paginated %}class="pagination">{% if page_obj.has_previous %}class="page-item">class="page-link" href="?page={{ page_obj.previous_page_number }}">?{% else %}class="page-item disabled">class="page-link">?{% endif %} {% for i in paginator.page_range %} {% if page_obj.number == i %}class="page-item active">class="page-link"> {{ i }} class="sr-only">(current){% else %}class="page-item">class="page-link" href="?page={{ i }}">{{ i }}{% endif %} {% endfor %} {% if page_obj.has_next %}class="page-item">class="page-link" href="?page={{ page_obj.next_page_number }}">?{% else %}class="page-item disabled">class="page-link">?{% endif %}{% endif %}{% endblock %}
查看效果
我們們在article_detail.html加入{% load blog_extras %}和?{% show_monthly_archive %}, 這時的文章詳情頁面就包含月度歸檔信息了。點擊鏈接可以查看每月文章列表。
最后的話
統計哪些月份是否表了文章以及每個月發表了多少篇文章是非常耗時的運算。如果用戶每訪問一個頁面,都需要重新計算一次會造成很大的資源浪費。這部分信息其實更新的并不是那么快,完全可以使用緩存把計算結果緩存起來,如下所示。更多內容見Django基礎(8): 緩存Cache應用場景及工作原理,Cache設置及如何使用。
#在模板中使用cache
{% load cache %}{% cache 500 %}
{% show_monthly_archive %}
{% endcache %}你有更好的實現辦法嗎? 如果你有什么功能或業務需求需要實現的,歡迎留言。小編我會根據個人興趣有選擇性地提供解決方案。
大江狗
2019.09.21
總結
以上是生活随笔為你收集整理的template标签_Django实战: 利用自定义模板标签实现仿CSDN博客月度归档的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: TP-Link路由器设置上网知识笔记
- 下一篇: 电商数据分析Excel案例