2、Django框架二
模版技术
模版技术
Django模版
Django模版基础配置
模版文件基础
基础模版语言
模版渲染
模版渲染快捷方法
Django模版语言
模版变量
模版列表
模版字典
模版字典查找顺序
Django模版标签
逻辑判断标签
循环处理
Django模版过滤器
常见过滤器
自定义过滤器
模版技术
Django模版
Django模版基础配置
模版文件基础
基础模版语言
模版渲染
模版渲染快捷方法
Django模版语言
模版变量
模版列表
模版字典
模版字典查找顺序
Django模版标签
逻辑判断标签
循环处理
Django模版过滤器
常见过滤器
自定义过滤器
模版技术
Django框架在进行路由匹配之后,会映射到一个可调用对象,一般为视图函数,在处理函数中,有使用过HttpResponse对象和JsonResponse对象,这些东西相对于来说,比较简单,要么给客户端返回一个HTML文档,要么客户端返回一个JSON数据;
对于这种响应报文的主体部分,有两种用法,第一种是完全在Django中不实现任何HTML页面,纯粹给客户端返回一个JSON数据,将Django作为一个数据源的角色,这是一种方式,还有一种方式,就是在视图处理函数里面,找到一个HTML文档,然后返回给客户端使浏览器进行渲染;
那么对于模版来讲,它说的就是上面说的第二种方式,即,返回一个HTML文档,当然,加入了模版这个元素之后,这个HTML文档,就不是一个简单的HTML文档了,对于这个HTML文档里面有一部分是一些占位符,类似我们的字符串格式化一样,它在Django里面叫做,模版字符,如下;
# views.py
class Home(View):
def get(self, request):
data = {"name": "cce", "age": 10}
template_file="<html><body><h1>My Name Is {name} and Age Is {age}</h1></body></html>"
response_body = template_file.format(**data)
return HttpResponse(response_body)
# urls.py
urlpatterns = [
path('index/', Home.as_view()),
]
模版技术
可以看到上面就是通过字符串格式化实现的模版技术,其实如果希望更加明显一点,我们可以将变量template_file的内容设置成一个HTML文件,这样这个HTML文件就成为了,我们所谓的"模版文件",然后使用open()方法将这个"模版文件"读取出来,随后通过传入的data数据,进行HTML文档的动态的包装,从而形成一个完整的HTML文档,这样更符合模版的特性,只不过上述这样实现只是为了笔记是美观性;
其实这就是模版技术,但是上述,我们仅仅只能实现,基础的占位符替换,那么如果我们期望更加复杂的处理,比如在模版文件里面对传入进来的数据进行判断、进行循环等等,使用这种字符串格式化方式是不行的,那么这个时候,就形成了一种更加高级的技术了,即,模版技术,但是本质上就是上面这样,通过替换的方式,将内容填充到占位符;
常见的模版技术有,JSP、ASP 、PHP和.NET,那么在Django中,也提供了模版技术的支持,它们实际上就是在HTML文档里面写入一些模版字符串,然后在正式构建Response报文之前,将模版字符串替换成真正的的数据,其实都是这么一个实现思路;
Django模版
对于Django的模版,就底层实现的方式,和上面没什么区别,只不过对于Django模版来讲,将模版字符串放在一个HTML文档里面,从而形成HTML模版,然后在返回响应报文之前,将这个HTML模版进行格式化,将HTML模版里面的模版字符串替换成我们期望的数据,形成一个HTML完整的文档,这一套逻辑,进行了封装,封装成一种模版语言,同时也支持了更多的特性,比如常见的字符判断、循环、切割等技术,这就是Django中的模版技术;
Django模版基础配置
在Django中提供了一套模版语言技术,称之为Django Template Language(DTL),对于Django的模版技术,分几步,第一步加载HTML模版文件,然后进行占位符替换,最后封装成一个HTTP的Response对象;
那么对于Django中的模版来讲,一般在创建一个Django项目时,会提供一些默认设置,它规定了模版应该如何解析,如何检索等,其实我们只需要关注下面前三个配置即可,如下;
# settings.py
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
# 解释
BACKEND:它为一个完整的路径,主要用途为指定Django使用的模版引擎,主要有两种,如下;
django.template.backends.django.DjangoTemplates
django.template.backends.jinja2.Jinja2
DIRS:这是一个列表,在这个列表中可以存放所有的模板路径。以后在视图中使用render()或者render_to_string()渲染模板的时候,就会在这个列表的路径中查找模板。即Django会默认的在这个列表中配置的路径下去寻找模板;
APP_DIRS:默认值为True,这个设置为True,会在INSTALLED_APPS配置中的所有的app下的templates文件夹中查找模板,这也就是为什么在创建一个App后,需要在INSTALLED_APPS中注册这个app的原因之一;
OPTIONS:传递给该模板引擎(backend)的其他参数,不同的引擎,可用的参数不一样,无需详细了解;
模版文件基础
对于Django来讲,默认存储模版文件的目录名称为"templates",那么根据上面配置的解释来看,一般情况下,我们只需要在App目录下面创建一个名为"templates"的目录存储模版文件即可,因为TEMPLATES配置的APP_DIRS的值默认为True,无需修改任何配置,如下;
[cce@doorta ~]# tree /usr/local/Project/blog
/usr/local/Project/blog
├── blog
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── manage.py
└── user
├── __init__.py
├── admin.py
├── apps.py
├── migrations
│ ├── __init__.py
├── models.py
├── templates # 模版文件夹
│ └── index.html # 模版文件
├── tests.py
└── views.py
基础模版语言
为了能更好的演示模版的基础流程,首先先来看下Django模版语言的基础占位符替换语法,如果只是做字符替换其实很简单,它和我们的字符串很类似,在模版文件中,我们的变量可以使用双大括号包裹一个变量名来表示,如{{ name }},这就是Django模版语言中占位符的表示方法,如下;
# 模版文件
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
{{ name }}%
模版渲染
Django模版的解析流程第一步就是加载模版,即,在模版目录下面检索到指定路径或者名称的模版,Django提供了一个loader类,该类在django.template包下,该类下面提供了一个get_template()方法,该方法首先会找到这个模版的位置,然后将这个模版加载;
同时get_template()方法返回一个django.template.backends.django.Template对象,该对象所属的类就是提供模版渲染的类,它下面有一个render方法,该方法主要就是用来进行模版渲染的,它的返回值就是替换完成之后的完整的HTML文档,如下;
# /usr/local/Project/blog/user/templates/index.html
My Name Is {{ name }} and Age Is {{ age }}
# views.py
class Home(View):
def get(self, request):
data = {"name": "cce", "age": 18}
template_file_content = get_template("index.html")
return HttpResponse(template_file_content.render(data))
可以看到,render()方法,将这个模版文件进行渲染之后,成功的进行了占位符替换完成,返回了一个替换完成之后的一个完整的HTML文档字符串,然后使用HttpResponse对象对HTML文档字符串封装成一个Response对象,然后返回给客户端,浏览器也成功的显示了一个在后端进行渲染完成的HTML文档;
模版渲染快捷方法
因为django.template.backends.django.Template下面render方法,返回的是一个django.utils.safestring.SafeText对象,通过源码可以看到,该对象就是一个str方法的子类,说白了,返回的就是经过占位符替换完成之后一个完整的HTML文档格式的字符串,所以它并非是一个封装后的HTTP Response对象,因此,我们还是需要使用HttpResponse类将其封装成一个Response对象;
class SafeText(str, SafeData):pass
那么Django为了方便开发者,提供了一个更加方便的方法,该方法在django.shortcuts模块下,名为render,源码如下,将占位符替换完成之后的完整的HTML文档字符串使用HttpResponse类封装成一个HTTP对象;
def render(request, template_name, context=None, content_type=None, status=None, using=None):
content = loader.render_to_string(template_name, context, request, using=using)
return HttpResponse(content, content_type, status)
因此,我们就可以直接使用该方法进行模版字符串的渲染,和HTTP响应报文的封装,这个render比get_template()方法返回的Template对象下的rander()更加的方便,如下;
# /usr/local/Project/blog/user/templates/index.html
My Name Is {{ name }} and Age Is {{ age }}
# views.py
class Home(View):
def get(self, request):
data = {"name": "cce", "age": 18}
return render(request, 'index.html', data, status=201)
- 注意:
此外,在django.shortcuts模块下,还提供了一个render_to_response()方法,它render()方法其实差不多,只不过,如果我们希望在模版中使用我们request对象里面的一些属性时,我们可以直接使用render()方法,当然,如果只做占位符替换,我们也可以使用render_to_response()方法来实现;
Django模版语言
Django模版语言,即DTL语法,在上面了解了模版技术的底层实现之后,开始了解模版语言,模版语言,主要有三类,模版基本数据类型(变量、列表、字典)、模版标签和模版过滤器;
那么为了方便实验,也为了笔记的美观性,我们就将视图处理函数统一,后面的所有的模版语言基础数据类型的实验,全部都适用于如下视图处理函数;
# views.py
from django.shortcuts import render_to_response as render
import datetime
class Home(View):
def get(self, request):
data = {
"name": "cce",
"members": ["cce", "cfj", "dxf"],
"parents": [
{"name": "cfj"},
{"name", "dxf"}
],
"info": {
"hobby": ["游泳", "打球"],
"birthday": datetime.datetime(1996, 4, 26, 00, 00, 00)
}
}
return render('index.html', data, status=201)
# urls.py
urlpatterns = [
path('', Home.as_view()),
]
模版变量
对于Django模版语言中的变量来说,它以两个大括号包裹一个变量名称的方式表示变量语法,如:{{ name }},如下;
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
基础变量:{{ name }}
[cce@doorta ~]# curl http://127.0.0.1:8000/
基础变量:cce
模版列表
在Django模版中,如果我们期望能够访问一个列表中的元素,和Python中的列表是一样的,都是通过索引的方式去查找,但是,我们需要注意的是,在Django模版语言中,索引号,是以一个属性的方式存在,所以在Django的模版语言中,如果我们需要访问一个列表中指定索引号的数值时,语法格式为,"list_name.index";
- 注意:
可以看到下面的结果中,很多"&#"这样的特殊字符,这是因为模版语言将我们的冒号转换了;
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
基础变量:{{ parents.0 }}%
[cce@doorta ~]# curl http://127.0.0.1:8000/
基础变量:{'name': 'cfj'}%
- 注意:
需要注意,index默认从0开始,且不可为负数;
模版字典
因为Django模版,对模版语言做了处理,在模版中,不能使用原生的字段语法获取字典中的键值对,它将字典封装成了一个对象,如果我们需要在模版中需要获取字典中的值时,值需要使用对象的方式访问即可,无法通过字典的方式来访问,如下;
- 注意:
可以看到下面的结果中,很多"&#"这样的特殊字符,这是因为模版语言将我们的冒号转换了;
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
基础变量:{{ info.birthday }}
[cce@doorta ~]# curl http://127.0.0.1:8000/
基础变量:1996年4月26日 00:00
如果我们希望访问到字典里面所有的key,那么我们可以直接访问这个字典对象的keys属性,但是需要注意一点,后面没有括号"()",在模版语言中,括号都去掉了,如下;
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
基础变量:{{ info.keys }}%
[cce@doorta ~]# curl http://127.0.0.1:8000/
基础变量:dict_keys(['birthday', 'hobby'])%
如果希望访问到字典里面所有的values,那么我们可以直接访问这个字典对象的values属性,但是需要注意一点,后面没有括号"()",在模版语言中,括号都去掉了,如下;
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
基础变量:{{ info.values }}%
[cce@doorta ~]# curl http://127.0.0.1:8000/
基础变量:dict_values([datetime.datetime(1996, 4, 26, 0, 0), ['游泳', '打球']])%
如果希望访问到字典里面的keys和values的组合,那么我们可以直接访问这个字典对象的items属性,但是需要注意一点,后面没有括号"()",在模版语言中,括号都去掉了,如下;
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
基础变量:{{ info.items }}%
[cce@doorta ~]# curl http://127.0.0.1:8000/
基础变量:dict_items([('birthday', datetime.datetime(1996, 4, 26, 0, 0)), ('hobby', ['游泳', '打球'])])%
模版字典查找顺序
默认情况下,Django模版语言对于字典的查找方式很特殊,首先在Django模版中,只允许使用类似Python对象的方式来访问,假设我们需要访问字典的keys,即使{{ info.keys }},那么它首先会访问这个info对象下面是否有keys属性,如果没有会访问这个info字典下面是否存在名为"keys"的键,这就是Django模版语言的字典查找方式;
Django模版标签
模版标签,主要用于一些复杂的数据处理的方法,如逻辑判断语句、循环语句等,它采用单大括号结合百分号的方式表示,如果{% tag %};
逻辑判断标签
逻辑判断标签,所谓逻辑判断,就是我们平常使用的IF语句,它一样支持单分支、多分支,同时它也支持很多的判断运算符,如常用的大于、小于、等于等,那么常用的一些判断运算符如下;
操作符
|
意义
|
==
|
等值判断
|
!=
|
不等值判断
|
<
|
小于判断
|
>
|
大于判断
|
<=
|
小于等于判断
|
>=
|
大于等于判断
|
in
|
包含判断
|
not in
|
不包含判断
|
and
|
与
|
or
|
或
|
not
|
非
|
可以看到这些操作符,其实和我们的Python语言中的一些操作符基本是一摸一样的,大部分也是继承自Python的特点而来的,如下示例;
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
{% if "yml" in members %}
<h1>张三</h1>
{% elif 'cfj' in members %}
<h1>李四</h1>
{% else %}
<h1>王五</h1>
{% endif %}%%
[cce@doorta ~]# curl http://127.0.0.1:8000/
<h1>李四</h1>
- 提示:
其实在Django的模版语言中,提供的逻辑判断语句还有很多,如ifchanged、ifequal、ifnotequal,但是由于模版技术其实后面用得不是太多,所以这些直接看Django的官方文档吧;
循环处理
对于Django模版语言来讲,它也是一种基础语言,所以在这个语言中,也支持了循环语句,即For语句,用于循环Python内所有可以迭代的对象;
那么对于For循环来讲,Django模版语言中添加了一些可能会用到的属性,如下;
forloop.counter:当前循环的下标。以1作为起始值;
forloop.counter0:当前循环的下标。以0作为起始值;
forloop.revcounter:当前循环的反向下标值。比如列表有5个元素,那么第一次遍历这个属性是等于5,第二次是4,以此类推。并且是以1作为最后一个元素的下标;
forloop.revcounter0:类似于forloop.revcounter。不同的是最后一个元素的下标是从0开始;
forloop.first:是否是第一次遍历;
forloop.last:是否是最后一次遍历;
forloop.parentloop:如果有多个循环嵌套,那么这个属性代表的是上一级的for循环;
如下示例,循环迭代出一个列表中的数据,并记录每一次循环的行号;
[cce@doorta ~]# cat /usr/local/Project/blog/user/templates/index.html
{% for x in members %}
<p>{{ x }}</p>
<span>{{ forloop.counter0 }}</span>
{% endfor %}%
[cce@doorta ~]# curl http://127.0.0.1:8000/
<p>cce</p>
<span>0</span>
<p>cfj</p>
<span>1</span>
<p>dxf</p>
<span>2</span>
- 注意:
模版语言下面的模版标签其实还有很多,因为后期大多数情况下都是使用前后分离的形式开发,所以在此就不过多赘述,详情请查看官方文档;
Django模版过滤器
过滤器从字面的意思上,可以理解为,过滤掉不需要的,剩下我们需要的,Django的模板语言同样也内置了过滤器,过滤器作用是在变量输出时,对输出的变量值做进一步的处理,比如,我们可以使用过滤器来更改变量的值;
过滤器跟模板标签一样,也是在模板中对函数进行调用,比如,对输出的日期进行格式化处理,或者转换大小写字母等,这些都有对应的过滤器去处理它们。当内置过滤器满足不了需求的情况下,也可自定义过滤器。过滤器的语法格式如下;
{{ 变量 | 过滤器1:参数值1 | 过滤器2:参数值2 ... }}
从语法格式我们可以得知过滤器使用|管道符进行变量与过滤器之间的连接,过滤器的可以通过组合多个过滤器实现链式调用,目前过滤器最多接受一个参数;
常见过滤器
过滤器相比模板标签要简单的多,我们可以把它们理解成一个Python函数,传递参数给他处理就可以了,当滤器接收参数后对它进行处理,最终将处理结果返回到模板中,这就是整个过滤器的实现流程;
那么对于Django模版语言来讲,它也提供了很多内置过滤器,如下;
过滤器
|
使用说明
|
length
|
获取变量的长度,适用于字符串和列表
|
lower/upper
|
转换字符串为小写/大写形式
|
first/last
|
获取变量的首个/末尾元素
|
add:”n“
|
数值加法,给变量值增加n
|
safe
|
默认不对变量内的字符串进行html转义
|
cut:” “
|
从给定的字符串中删除指定的值
|
dictsort:”age”
|
获取字典列表,并返回按参数中给定键排序的列表
|
join:”/”
|
用字符串连接列表,例如 Python 的 str.join(list)
|
truncatewords:’n‘
|
如果字符串字符多于指定的字符数量,那么会被截断。 截断的字符串将以可翻译的省略号序列(“…”)结尾
|
capfirst
|
将值的第一个字符大写。如果第一个字符不是字母,则此过滤器无效
|
default
|
定义默认值,如果value值为空,则使用给定的默认值;
|
divisibleby:’n’
|
判断变量是否可以被n整除,返回布尔值
|
escape
|
转义字符串的HTML,此转换器会将<转换为<,>转换为>等
|
自定义过滤器
自定义过滤器也非常简单,也是考虑到后期使用Django模版这种方式去渲染HTML文档的情况很少,同时我们也不推荐在模版语言中去做过多的数据处理,正常情况下,我们应该在Django的视图处理函数层面将数据直接处理好,然后拿着处理好的数据进行模版占位符替换,因此对于自定义过滤器不做过多赘述,详细定义语法,查询官方文档即可;