Django2.X—Django模板引擎

Django模板引擎

Django内置的模板引擎包含模板上下文(亦可称为模板变量)、标签和过滤器,各个功能说明如下:

  • 模板上下文是以变量的形式写入模板文件,变量值由视图函数或视图类传递所得
  • 标签是对模板上下文进行控制输出,比如模板上下文的判断和循环控制等。
  • 模板继承隶属标签,它是将每个模板文件重复代码抽取出来并写在一个共用的模板文件中,其他模板文件通过继承共用模板文件夹实现完整的网页输出。
  • 过滤器是对模板上下文进行操作处理,比如模板上下文的内容截取、替换或格式转换等。

1、 模板上下文

模板上下文是模板中基本的组成单位,上下文的数据由视图函数或视图类传递。它以{{variable}}表示,variable是上下文名称,它支持Python所有的数据类型,如字典、列表、元组、字符串、整型和实例化对象。上下文的数据格式不同,在模板里使用方式也有所差异,如下所示:

# 假如variable1 = '字符串或整型'
<div>{{variable}}</div>
# 输出"<div>字符串或整型</div>"

# 假如variable2={'name':'字典或实例化对象'}
<div>{{variable2.name}}</div>
# 输出"<div>字典或实例化对象</div>"

# 假如variable3=['元组或列表']
<div>{{vaiable3}}</div>
# 输出"<div>元组或列表</div>"

如果视图没有模板上下文传递数据或者模板上下文的某个属性、索引下标不存在,Django会将其设为空值。

2、 自定义标签

标签是对模板上下文进行控制输出,它是以{% tag %}表示的,其中tag是标签的名称,Django内置了许多模板标签,比如{% if %}(判断标签)、{% for %}(循环标签)或{% url %}(路由标签)等。
常用的内置标签:

标签 描述
{% if %} 遍历输出上下文的内容
{% for %} 对上下文进行条件判断
{% csrf_token %} 生成csrf_token 的标签,用于防护跨站请求伪造攻击
{% url %} 引用路由配置的地址。生成相应的路由地址
{% wiht %} 将上下文重新命名
{% load %} 加载导入Django的标签库
{% static %} 读取静态资源的文件内容
{% extends xxx %} 模板继承,xxx为模板文件名,使当前模板继承xxx模板
{% block xxx %} 重写父类模板的代码

在上述常用标签中,每个标签的使用方法都是各不相同,通过简单的例子进一步了解标签的使用方法,代码如下:

# for标签,支持嵌套,myList可为列表、元组或某个对象
# item可自定义命名,代表当前循环的数据对象
# {% endfor %}是循环区域终止符,代表着区域的代码由标签for输出
{% for item in myList %}
{{ item }}
{% endfor %}

# if标签,支持嵌套
# 判断条件与上下文之间使用空格隔开,否则程序会抛出异常
# {% endif %}与{% endfor %}的作用是相同的
{% if name=="Lily" %}
{{name}}
{% elif name=="Lucy" %}
{{name}}
{% else %}
{{name}}
{% endif %}

# url标签
# 生成不带变量的URL地址
<a href="{% url 'index' %}">首页</a>
# 生成带变量的URL地址
<a href="{% url 'page' 1 %}">第1页</a>

# with标签,与Python的with的语法的功能相同
# total=number无须空格隔开,否则抛出异常
{% with total=number %}
{{ total }}
{% endwith %}

# load标签,导入静态文件标签库staticfiles
# staticfiles来自settings.py的INSTALLED_APPS
{% load staticfiles %}

# static标签,来自静态文件标签库staticfiles
{% static "css/index.css" %}

在for标签中,模板还提供了一些特殊的变量来获取for标签的循环信息,变量说明如下:

变量 描述
forloop.counter 获取当前循环的索引,从1开始计算
forloop.counter0 获取当前循环的索引,从0开始计算
forloop.revcounter 索引从最大数开始递减,直到索引到1位置
forloop.revcounter0 索引从最大数开始递减,直到索引到0位置
forloop.first 当遍历的元素为第一项时为真
forloop.last 当遍历的元素为最后一项时为真
forloop.parentloop 在嵌套的for循环中,获取上层for循环的forloop

上述变量来自于forloop对象,该对象是在模板引擎for标签时生成的,通过以下例子进一步了解forloop,例子如下:

{% for name in name_list %}
{% if forloop.counter == 1 %}
<span>这是第一次循环</span>
{% elifforloop.last %}
<span>这是最后一次循环</span>
{% else %}
<span>本次循环次数为:{{forloop.counter}}</span>
{% endif %}
{% endfor %}

除了使用内置的模板标签之外,还可以自定义模板标签。 以MyDjango为例,在项目的根目录创建新的文件夹,文件夹名称可称自行命名,本示例命名为mydefined;然后在该文件下创建初始化文件_init_.py和templatetags文件夹,其中templatetags文件夹的命名是固定不变的;最后在templatetags文件里创建初始化文件_init_.py和自定义标签文件mytags.py,项目的目录结构如图:
在这里插入图片描述
由于在项目的根目录下创建了mydefined文件夹,因此在配置文件settings.py的属性INSTALLED_APPS里添加mydefined,否则Django在运行时无法加载mydefined文件夹的内容。配置信息如下:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'index',
    # 添加自定义模版标签的文件夹
    'mydefined'
]

下一步在项目的mytags.py文件里自定义标签,我们将定义一个名为reversal的标签,它是将标签里的数据进行反转处理,定义过程如下:

from django import template
# 创建模版对象
register = template.Library()

# 定义模版节点类
class ReversalNode(template.Node):
    def __init__(self, value):
        self.value = str(value)

    # 数据反转处理
    def render(self, context):
        return self.value[::-1]

# 声明并定义标签
@register.tag(name='reversal')
# parse是解析器对象,token是被解析的对象
def do_reversal(parse, token):
    try:
        # tag_name是代表标签名,即reversal
        # value是由标签传递的数据
        tag_name, value = token.split_contents()
    except:
        raise template.TemplateSyntaxError('syntax')
    # 调用自定义的模板节点类
    return ReversalNode(value)

在mytags.py文件里分别定义类ReversalNode和函数do_reversal,两者实现功能说明如下:

  • 函数do_reversal经过装饰器register.tag(name=‘reversal’)处理,这是让函数执行模板标签注册,标签名称由装饰器参数name进行命名,如果没有设置参数name,就以函数名作为标签名称。函数名没有具体要求,一般以 “do_标签名”“标签名称” 作为命名规范。
  • 函数参数parse是解析对象,当Django运行时,它将所有标签和过滤器进行加载并生成到parse对象,在解析模板文件里面的标签时,Django就会从parse对象查找对应的标签信息。
  • 函数参数token是模板文件使用标签时所传递的数据对象,主要包括标签名和数据内容。
  • 函数do_reversal对参数token使用spilt_contents()方法(Django内置方法)进行取值处理,从中获取数据value,并将value传递给自定义模板节点类ReversalNode。
  • 类ReversalNode是将value执行字符串反转处理,并生成模板节点对象,用于模板引擎解析HTML语言。

为了验证自定义标签reversal的功能,我们在index的urls.py、views.py和模板文件index.html里编写以下代码:

# index的url.py
from django.urls import path
from .views import *
urlpatterns = [
    # 定义路由
    path('', index, name='index'),
]


# index的views.py
from django.shortcuts import render
def index(request):
    return render(request, 'index.html', locals())


# templates的index.html
{#导入自定义标签文件mytags#}
{% load mytags %}
<!DOCTYPE html>
<html>
<body>
{% reversal 'Django' %}
</body>
</html>

在模板文件index.html中使用自定义标签,必须使用{% load mytags %}将自定义标签文件导入,告知模板引擎从哪里查找自定义标签,否则无法识别自定义标签,并提示TemplateSyntaxError异常。
总结:

  • 自定义标签需要在项目里搭建目录环境。
  • 在使用时需要在模板文件里导入自定义标签文件。

3、 模板继承

模板继承是通过模板标签来实现的,其作用是将多个模板文件的共同代码集中在一个新的模板文件中,然后各个模板可以直接调用新的模板文件,从而生成HTML网页,这样可以减少模板之间重复的代码,范例如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
 <title>{{ title }}</title>
 </head>
<body>
	<a href="{% url "index:index" %}">首页</a>
	<h1>Hello Django</h1>
</body>
</html>

上述代码是一个完整的模板文件,一个完整的模板通常有<head>和<body>两部分,而每个模板的<head>和<body>的内容都会有所不同,因此除了这两部分的内容之外,可以将其他内容写在共用模板文件里。
以MyDjango为例,在templates文件夹里创建base.html文件,该文件作为共用模板,代码如下:

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
{% block title %}
    <title>首页</title>
{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>

在base.html的代码中看到,<title>写在模板标签{% block title %}{% endblock %}里面,而<body>里的内容改为{% block title %}{% endblock %}。block标签是为其他模板文件调用时提供内容重写的接口,body是对这个接口进行命名。在一个模板中可以添加多个block标签,只要每个block标签的命名不相同即可。接着在模板index.html中调用共用模板base.html,代码如下:

{% extends "base.html" %}
{% block body %}
<a href="{% url 'index:index' %}">首页</a>
<h1>Hello Django</h1>
{% endblock %}

模板index.html调用共用模板base.html的实质是由模板继承实现的,调用步骤如下:

  • 在模板index.html中使用{% extends “base.html” %}来继承模板base.html的所有代码。
  • 通过使用标签{% block title %}或{% block body %}来重写模板base.html的网页内容。
  • 如果没有使用标签block重写共用模板内容,网页内容将由共用模板提供,比如模板index.html没有使用标签{% block title %}重新定义<title>,那么网页标题内容应由模板base.html设置<title>提供。
  • 标签block必须使用{% endblock %}结束block标签。

从模板index.html看到,模板继承鱼Python的类继承原理一致的,通过继承方式使具有父类的功能和属性,同时也可以通过重写来实现复杂多变的开发需求。
结果展示:
在这里插入图片描述

4、 自定义过滤器

过滤器是对上下文的内容进行操作处理,如替换、反序和转义等。通过处理器上下文可以将数据格式或内容转化为我们想要的显示效果,而且相应减少视图的代码量。过滤器的使用方法如下:

{{ variable | filter }}

若上下文设有过滤器,则模板引擎在解析上下文时,首先由过滤器filter处理上下文variable,然后将处理后的结果进行解析并显示在网页上。variable代表模板上下文,管道符号"|"代表当前上下文使用过滤器,filter代表过滤器。单个上下文可以支持多个过滤器同时使用,例如:

{{ variable | filter | lower }}

在使用的过程中,有些过滤器还可以传入参数,但仅支持传入一个参数。带参数的过滤器与参数之间使用冒号隔开,并且两者之间不能留有空格,例如:

{{ variable | date:"D d M Y"}}

Django的内置过滤器可以在源码(\django\template\defaultfilters.py)里找到具体的定义过程。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章