在Django基础(15): 模板过滤器(filter)的工作原理及如何自定义模板过滤器中我们已经介绍了Django模板过滤器(filter)的本质及工作原理, 并详细讲解了如何自定义模板过滤器。今天小编我就来讲下Django模板标签(tags)的分类及如何自定义模板标签。

什么是模板标签(tags)

模板标签都是放在{%  %}括号里的,常见的模板标签有{% load xxxx %}, {% block xxxx %}, {% if xxx %}, {% url 'xxxx'  %}。这些模板标签的本质也是函数,标签名一般即为函数名。这些标签的主要作用包括载入代码渲染模板或对传递过来的参数进行一定的逻辑判断或计算后返回。

比如下例中的url标签接收两个参数,一是命名的url, 一个是文章id,将其进行反向解析,生成一个类似blog/article/4/的链接。

<a href="{% url 'blog:article_detail' article.id  %}">详情</a>

Django模板标签(tags)的分类

Django的模板标签(tag)一共分2类:

  • simple_tag (简单标签 : 处理数据,返回一个字符串或者给context设置或添加变量。

  • inclusion_tag (包含标签) : 处理数据,返回一个渲染过的模板。

熟悉Django的都知道,我们一般在视图view里设置context,然后通过它来传递数据给模板。 一个context是一系列变量和它们值的集合。通过使用simple_tag, 我们可以在视图外给context设置或添加变量。注: Django 1.9以后不再支持assignment_tag了,均使用simple_tag。

如何自定义模板标签

首先你要在你的app目录下新建一个叫templatetags的文件夹(不能取其它名字), 里面必需包含__init__.py的空文件。在该目录下你还要新建一个python文件专门存放你自定义的模板标签函数,本例中为blog_extras.py,当然你也可以取其它名字。整个目录结构如下所示:

blog/__init__.pymodels.pytemplatetags/__init__.pyblog_extras.pyviews.py

在模板中使用自定义的模板标签时,需要先使用{% load blog_extras %}载入自定义的过滤器,然后通过{% tag_name %} 使用它。

自定义模板标签的3个简单例子

我们将定义3个简单模板标签,一个返回string, 一个给模板context传递变量,一个显示渲染过的模板。我们在blog_extra.py里添加下面代码。

#blog_extra.py

from django import template
import datetime
from blog.models import Articleregister = template.Library()# use simple tag to show string
@register.simple_tag
def total_articles():return Article.objects.filter(status='p').count()# use simple tag to set context variable
@register.simple_tag
def get_first_article():return Article.objects.filter(status='p').order_by('-pub_date')[0]# show rendered template
@register.inclusion_tag('blog/latest_article_list.html')
def show_latest_articles(count=5):latest_articles = Article.objects.filter(status='p').order_by('-pub_date')[:count]return {'latest_articles': latest_articles, }

# latest_article_list.html

<ul>
{% for article in latest_articles %}
<li>{{ article.title }} </li>
{% endfor %}
</ul>

# index.html (使用我们自定义的模板标签)

{% extends "blog/base.html" %}
{% load blog_extras %}{% block content %}<p>文章数: {% total_articles %}</p>
{% show_latest_articles %}{% get_first_article as first_article %}
<p>第一篇文章: </p>
<p>{{ first_article.title }}</p>{% endblock %}

最后展示效果图如下所示:

一个复杂的例子: 从模板或context接收参数后返回结果

上述3个简单例子的信息传递都是单向的,更常见的情况是标签函数接收从模板或context传递过来的参数,处理后再返回字符串或渲染过的模板。

下例中show_results标签需要接收模板传递的poll这个参数,才能返回poll结果。

{% show_results poll %}

这时我们可以这样写show_results函数。

@register.inclusion_tag('results.html')
def show_results(poll):choices = poll.choice_set.all()return {'choices': choices}

当然poll这个变量出现在模板中并不是必需的,很多时候一个对象或一个对象清单已经存在全局变量context里,我们可以使用takes_context=True来直接使用context里的变量。假设poll已经存在context里,我们上面代码可以改为:

@register.inclusion_tag('results.html', takes_context=True)
def show_results(context):choices = context['poll'].choice_set.all()return {'choices': choices}

此时模板可以简化为如下代码,不再需要poll这个参数,即可显示poll的结果。

{% show_results %}

如何处理从模板中传递过来的多个参数

{% show_results poll %}中我们自定义的标签函数只接收了从模板传递过来的一个poll参数。一个模板也可以传递多个参数,如果参数名字或数量已知,Django的tag函数是可以按位置处理传递过来的参数的。

{% my_tag "abcd" book.title warning=message profile=user.profile %}@register.inclusion_tag('my_template.html')
def my_tag(a, b, *args, **kwargs):warning = kwargs['warning']profile = kwargs['profile']...return ...

但类似{% url "article_detail" article.id article.slug %}中的url标签显然要复杂得多。它可以接收未知数量的参数和未知名字的参数, 而且参数中有的带双引号,有的不带双引号。

对于这种情况Django的做法是先对标签所在的节点进行解析(parser), 把接收过来的字符串整体作为一个token,先对token进行split拆分,然后再分别处理。

我们现在来看看{% format_time %}这个标签是如何时间日期的格式化的。

<p>Published at at {% format_time article.pub_date "%Y-%m-%d %I:%M %p" %}.</p>

自定义的format_time标签函数完整代码如下。

from django import templateregister = template.Library()@register.tag(name="format_time")
def do_format_time(parser, token):try:# split_contents() knows not to split quoted strings.tag_name, date_to_be_formatted, format_string = token.split_contents()except ValueError:raise template.TemplateSyntaxError("%r tag requires exactly two arguments" % token.contents.split()[0])if not (format_string[0] == format_string[-1] and format_string[0] in ('"', "'")):raise template.TemplateSyntaxError("%r tag's argument should be in quotes" % tag_name)return FormatTimeNode(date_to_be_formatted, format_string[1:-1])class FormatTimeNode(template.Node):def __init__(self, date_to_be_formatted, format_string):self.date_to_be_formatted = template.Variable(date_to_be_formatted)self.format_string = format_stringdef render(self, context):try:actual_date = self.date_to_be_formatted.resolve(context)return actual_date.strftime(self.format_string)except template.VariableDoesNotExist:return ''

我们现在来着重看下上面这段代码是如何工作的。

  • Django模板解析器扫描整个模板,碰到了format_time这个标签,把其当作一个新的节点Node,获取了format_time article.pub_date "%Y-%m-%d" 这一长串字符串作为token

  • get_format_time方法利用token自带的split_contents方法把上述字符串拆分成三部分: 标签名(tag_name), 需要格式化的日期(date)和指定格式(format), 并返回需要格式化的日期和格式交由FormatTimeNode处理。format_string[1:-1]的作用是去掉双引号。

  • FormatTimeNode这个节点类负责渲染节点,通过render方法渲染新的节点,还可以通过context给模板传递其它的变量(如下所示)。当render方法不返回一个具体的值的时候,需要返回一个空字符串。

def render(self, context):actual_date = self.date_to_be_formatted.resolve(context)context['formatted_time'] = actual_date.strftime(self.format_string)return ''

利用parse方法连续解析

有时你还会碰到{% comment %}和{% endcomment %}这样的标签。这时你就需要利用parse方法解析真个nodelist了。这个非常复杂,以后分析Django源码时会再做讲解。

小结

本文讲解了Django模板标签(tags)的2大类(simple tag和inclusion tag)及如何自定义模板标签,重点介绍了模板如何向标签函数传递一个或多个参数的原理。希望本文对你有所帮助。

大江狗

2018.9.19

Django基础(16): 模板标签(tags)的介绍及如何自定义模板标签相关推荐

  1. 模板标签(tags)的介绍及如何自定义模板标签

    什么是模板标签(tags) 模板标签都是放在{%  %}括号里的,常见的模板标签有{% load xxxx %}, {% block xxxx %}, {% if xxx %}, {% url 'xx ...

  2. Django基础核心技术之Model模型的介绍与设计

    Django基础核心技术之Model模型的介绍与设计 原创: Yunbo Shi Python Web与Django开发 2018-05-03 Django网络应用开发的5项基础核心技术包括模型(Mo ...

  3. Django基础---Web框架、URL路由、视图函数、模板系统

    文章目录 Django基础 Django基础---Web框架 MVC和MTV框架 MVC MTV Django下载与安装 基于Django实现一个简单的示例 get请求获取数据 post请求获取数据 ...

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

    应网友慕之岩的请求,现提供下Django项目中如何使用自定义标签实现仿CSDN博客的月度归档(如下图所示).要求按月统计每个月发表的博文篇数, 跳过空白月份,最后结果按发布时间逆序排列.点击每个月份可 ...

  5. Django基础(11): 表单集合Formset的高级用法详解

    Formset(表单集)是多个表单的集合.Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据,比如一个页面上添加多个用户信息.今天小编我就介绍下Djang ...

  6. 目标检测标注工具(可自定义生成标签模板)

    点击查看项目源码 全新升级,整改为JAR包运行模式,既然是java项目自然支持各个系统 下载JAR包 JDK版本要求:JDK8-JDK10 上不去github的戳这 CSDN 0积分下载 运行方式 j ...

  7. Android Studio自定义模板之MVPActivity

    前言 Android开发中经常需要创建Activity.一般情况下,咱们都是"New"->Java Class/Activity.但是Android Studio自带的Act ...

  8. MyBatisPlus3.x代码生成器自定义模板配置

    场景 MyBatisPlus3.x中使用代码生成器(全注释): https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/89518466 M ...

  9. php如何配置gii,深入浅析yii2-gii自定义模板的方法

    Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序.接下来通过本文给大家介绍yii2-gii自定义模板的方法,需要的朋友参考下吧 前言: Yii 是什么 Yii 是一个 ...

  10. 使用tld文件自定义jsp标签库

    目录 一,标签库描述文件(tld文件) 二,标签处理类 三,在JSP页面中使用自定义的标签 四,举个例子 通过Java的TagSupport类或者BodyTagSupport类,和配套的tld文件,可 ...

最新文章

  1. 工业4.0是个白日梦吗?
  2. PMP-【第3章 项目管理过程】-2021-1-11(61页-87页)
  3. 二、WPF datagrid 特定行变色
  4. C++设计模式之策略模式(Strategy)
  5. [Unity2018.2]ShaderGraph更新详解
  6. “培训班”出身的AI工程师,要得要不得?
  7. Golang + Qt5 桌面开发终极解决方案
  8. 对可道云KodExplorer去掉版权简单破解方法
  9. win10计算机磁盘图标,Win10系统硬盘图标怎么更换?Win10系统自定义硬盘图标的方法...
  10. 计算机公司客户电话怎么打,企业微信公费电话怎么打多人通话【方法】
  11. oracle 11g的Oracle Enterprise Manager(Oracle企业管理器,简称OEM)
  12. 共享充电宝还有市场嘛?
  13. Python 批量给图片添加水印小工具
  14. PWM(脉冲宽度调制)的工作原理、分类及其应用
  15. go 当前时间、时间戳和时间字符串及相互转换
  16. 前端框架系列之(eslint入门)
  17. Sentinel-Redis高可用方案(二):主从切换
  18. 计算机安全检查表,电脑安全自我检查表.doc
  19. 应用计算机散热的原理是什么,水冷散热器是什么原理?水冷可以带给机箱多大的散热作用?...
  20. 当容器遇上Ceph和Gluster……

热门文章

  1. Android 改变View的中心点
  2. CUDA 编程 __launch_bounds__的应用方法
  3. 笔记本电脑无线Wifi热点设置工具
  4. 帆软 finereport FCRA 考试 题库+答案,共收录561题,大部分有答案
  5. 怎么篡改网站html文件,首页被篡改-当我打开网页时,总是被其他网页给篡改了,我该怎么办? 爱问知识人...
  6. 计蒜客 青出于蓝胜于蓝 【DFS序 + 树状数组】
  7. 姿态估计mmpose一手体验 Ⅱ - 使用它!
  8. 金彩教育:拼多多运营的方法有哪些
  9. 嵌入式Linux--MYS-6ULX-IOT--总目录
  10. Kalrry记录---ing