template标签_Django实战: 利用自定义模板标签实现仿CSDN博客月度归档

应网友慕之岩的请求,现提供下Django项目中如何使用自定义标签实现仿CSDN博客的月度归档(如下图所示)。要求按月统计每个月发表的博文篇数, 跳过空白月份,最后结果按发布时间逆序排列。点击每个月份可以看到详细博文列表清单。本文着重讲述如何实现,不包括样式美化。如代码手机上看不全,可以搜索知乎大江狗或csdn大江狗。

09a89d7a2338f76dc893464439b2af2f.png

实现原理

假如我们有如下一个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 %}, 这时的文章详情页面就包含月度归档信息了。点击链接可以查看每月文章列表。

249988eb24d31e953761ba2e5adef040.png

最后的话

统计哪些月份是否表了文章以及每个月发表了多少篇文章是非常耗时的运算。如果用户每访问一个页面,都需要重新计算一次会造成很大的资源浪费。这部分信息其实更新的并不是那么快,完全可以使用缓存把计算结果缓存起来,如下所示。更多内容见Django基础(8): 缓存Cache应用场景及工作原理,Cache设置及如何使用。

#在模板中使用cache

{% load cache %}

{% cache 500 %}

{% show_monthly_archive %}

{% endcache %}

你有更好的实现办法吗? 如果你有什么功能或业务需求需要实现的,欢迎留言。小编我会根据个人兴趣有选择性地提供解决方案。

大江狗

2019.09.21

378527b3d7b9b519f01c1e588918ae5f.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/410542.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[html] 如何关闭HTML页面在IOS下的键盘首字母自动大写?

[html] 如何关闭HTML页面在IOS下的键盘首字母自动大写? autocapitalize"none"个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

javascript的stack overflow

写一个很简单的页面和脚本 1<html>2<head>3<title>fanweixiaos test</title>4<script type"text/javascript">5function onclick() 6{ 7 alert(范维肖); 8} 9</script>10</head>11<body>12<input type"b…

GLSL 小細節

"if-else" statement ""gl_FragColor""變數名稱""算指令數,迴圈的指令數要展開來算,才是真的指令數!!!!!!!!!!!!!!"不能下太多很像有限制.........假如出現無謂的ERROR 要注意這點!!!!!!!!!!!转载于:https://www.cnblogs.com/Gam…

Hibernate中inverse属性与cascade属性

Hibernate集合映射中&#xff0c;经常会使用到"inverse"和"cascade"这两个属性。对于我这样&#xff0c;Hibernate接触不深和语文水平够烂的种种因素&#xff0c;发现这两个属性实在是难以理解&#xff0c;无奈只好将这个两个属性解释工作交给了Google和Ba…

h5 nan_h5页面在不同ios设备上的问题总结

最近在写嵌入到小程序webview的一个h5页面&#xff0c;是一个文章评论的功能&#xff0c;这个过程中&#xff0c;遇到很多兼容性的问题&#xff0c;在不同机型上的表现也很不一致&#xff0c;所以总结了以下这些问题&#xff0c;记录下来&#xff0c;以便以后查看。1、日期问题…

[html] 写一个左中右的满屏布局,左右固定220px,中间自适应并且要优先加载

[html] 写一个左中右的满屏布局&#xff0c;左右固定220px,中间自适应并且要优先加载 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initia…

C# 淘宝商品微信返利助手开发-(七)返利助手开发(5)如何将优惠券地址转为淘口令

系列教程一目录&#xff1a;返利助手原理 系列教程二目录&#xff1a;返利助手开放文档以及帐号申请地址 系列教程三目录&#xff1a;返利助手开发&#xff08;1&#xff09;API介绍 系列教程四目录&#xff1a;返利助手开发&#xff08;2&#xff09;淘宝分享的内容如何只取…

什么是活动策划5表

昨晚&#xff0c;看了《非你莫属》&#xff0c;黄欢提到活动策划的五表。我以前也没听说过&#xff0c;不过现场她也没说清楚&#xff0c;今在网上查了一下&#xff0c;从一个博客中搬过来&#xff0c;权作一个指导工作的一个知识点吧。 活动流程表&#xff1b; 任务分工表&…

ftp改为sftp_科普!一文详解 FTP、FTPS 与 SFTP 的原理

FTP、FTPS 与 SFTP 简介FTPFTP 即 文件传输协议&#xff08;英语&#xff1a;File Transfer Protocol 的缩写&#xff09;是一个用于计算机网络上在客户端和服务器之间进行文件传输的应用层协议。完整的 FTP 是由 FTP 服务器 和 FTP 客户端组成的&#xff0c;客户端可以将本地的…

动手学servlet(四) cookie和session

Cookie cookie是保存在客户端的一个“键值对”&#xff0c;用来存储用户的一些信息 cookie的应用&#xff1a; -在电子商务会话中标识用户 -对网站进行定制&#xff0c;比如你经常浏览哪些内容&#xff0c;就展示哪些页面给你 -网站广告&#xff0c;比如百度联盟&#xff0c;你…

[html] html标签中的lang属性有什么作用?

[html] html标签中的lang属性有什么作用&#xff1f; 根据lang属性来设定不同语言的css样式&#xff0c;或者字体告诉搜索引擎做精确的识别让语法检查程序做语言识别帮助翻译工具做识别帮助网页阅读程序做识别等等个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识…

【C++ 学习笔记】:STL-map

查找 map<int,int>map_test;map_test.insert(pair<int,int>(1,2));map_test.insert(pair<int,int>(1,3));map_test.insert(pair<int,int>(2,2));inta map_test[1];intb map_test[3];map<int,int>::iterator p map_test.find(4);if(p map_test.en…

[html] 说说base标签有什么作用?

[html] 说说base标签有什么作用&#xff1f; base标签为页面上的所有链接规定默认地址. 例如<head> <base href"http://h-camel.com/show/" /> </head>//略过其中结构<a href"2679.html">说说base标签有什么作用</a>个人简…

16进制 转为图片 php_Python 十六进制hex-bytes-str之间的转换和Bcc码的生成

前言近期做测试模拟器用到了hex-bytes-str之间的转换bcc码的校验&#xff0c;这里总结了一些方法。实例直接上代码转为十六进制&#xff08;Hex&#xff09;字符串def 执行代码&#xff1a;方法&#xff1a;getStringFromNumber(size,value)参数一为生成几个batys&#xff0c;参…

C# 淘宝商品微信返利助手开发-(四)返利助手开发(2)淘宝分享的内容如何只取淘口令

系列教程一目录&#xff1a;返利助手原理 系列教程二目录&#xff1a;返利助手开放文档以及帐号申请地址 系列教程三目录&#xff1a;返利助手开发&#xff08;1&#xff09;API介绍 系列教程四目录&#xff1a;返利助手开发&#xff08;2&#xff09;淘宝分享的内容如何只取…

[html] 在head标签中必不少的是什么?

[html] 在head标签中必不少的是什么&#xff1f; 根据w3c文档&#xff0c;title是head 部分中唯一必需的元素。个人简介 我是歌谣&#xff0c;欢迎和大家一起交流前后端知识。放弃很容易&#xff0c; 但坚持一定很酷。欢迎大家一起讨论 主目录 与歌谣一起通关前端面试题

推荐一个国外SaaS产品-Olark

Olark www.olark.com 是国外非常出名的一个在线客服工具。 现在国内很多人创业失败的原因是&#xff1a;什么都想自己做&#xff0c;不利用现有资源&#xff0c;结果造成做出来的东西什么都有&#xff0c;什么都不好用。 我们应该好好学习国外的小团队&#xff0c;他们只做一件…

python sftp_python中实现sftp

python中想要实现sftp的话可以使用paramiko模块 paramiko很强大&#xff0c;通过python实现SSH协议。可以做到ssh远程登录&#xff0c;sftp上传下载文件。 sftp的实现 1.通过密码口令认证#!/usr/bin/python # -*- coding:utf-8 -*- import paramiko remotedir "/app/ftpu…

C# 淘宝商品微信返利助手开发-(三)返利助手开发(1)API介绍

系列教程一目录&#xff1a;返利助手原理 系列教程二目录&#xff1a;返利助手开放文档以及帐号申请地址 系列教程三目录&#xff1a;返利助手开发&#xff08;1&#xff09;API介绍 系列教程四目录&#xff1a;返利助手开发&#xff08;2&#xff09;淘宝分享的内容如何只取…

python之基础学习day01

今天是python学习的第一天&#xff0c;收获还是不少的&#xff0c;使用的编辑器为python3.7。 第一天学习知识总结&#xff1a; 1、编写的第一句python语句&#xff1a; print ( " hello world" ) 2、python的两种执行方式 --python解释器 py文件路径 --python进入解…