Django学习日志五:模板1
日志一我们学习了Django的配置,详见:
Django学习日志一Django的配置
日志二我们学习了创建第一个django项目,详见:
Django学习日志二——创建第一个django项目
日志三我们学习了django模型层,详见:
Django学习日志三:模型层
日志四我们学习了django视图层,详见:
Django学习日志四:视图层
下面我们来学习模板的使用:
七、模板
Django遵从MVC模式,其特色化为MVT模式,前文中讲解了M(models)模型和V(views)视图,本章会讲解T所代表的templates模板。
7.1 静态资源配置与加载
绝大多数Django网站都会使用模板语言来渲染HTML页面,并将该页面展示给客户端,其实模板就是经过特殊格式化后输出动态值的HTML文本,它支持简单的逻辑结构,如for循环、if或ifequal条件判断等。
在Django项目中要使用模板,需要通过如下3个不走进行配置。
步骤一:在工程目录hello中创建templates文件夹和static文件夹。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Q2147zWN-1647775787777)(C:\Users\天南之城\AppData\Roaming\Typora\typora-user-images\image-20220317204825363.png)]
步骤二:打开并编辑/hello/hello/setting.py文件,在setting.py文件中找到变量TEMPLATES并配置DIRS参数,配置代码如下:
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [os.path.join(BASE_DIR, 'templates')],
'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',
],
},
},
]
步骤三:打开编辑/hello/hello/setting.py文件,在setting.py文件最后一行添加STATICFILES_DIRS参数,配置代码如下:
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
上述配置完后,进行stus.html页面的编写,以及路由配置:
示例:查询并展示所有学生信息
在urls.py文件中定义路由
from django.urls import path
from app import views
urlpatterns = [
path(r'all_student/', views.all_student),
]
在views.py文件中定义视图函数
from django.shortcuts import render
from app.models import Student
def all_student(request):
if request.method == 'GET':
stus = Student.objects.all()
return render(request, 'stus.html', {'stus': stus})
在/hello/templates/目录下新建stus.html文件,页面代码如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>所有学生信息</title>
</head>
<body>
{% for stu in stus %}
<p>
学生id:{{stu.id}} 学生姓名:{{stu.s_name}}
</p>
{% endfor %}
</body>
</html>
分析:
在urls.py文件中定义路由地址,直接访问地址http://127.0.0.1:8080/all_student/会调用all_student()方法,在all_student()方法中使用Student模型进行数据查询,并调用render()方法返回stus.html页面和查询的学生数据。在stus.html页面解析stus参数,渲染出动态的效果。
7.2 模板继承
模板继承和python的类非常相似,可以通过继承的方式获取父模板中的所有元素,模板继承需要事先创建一个基本的“骨架”父模板,该基础模板中包含了网站的所有元素,并定义了可以被子模版覆盖的block。子模板通过继承事先定义的父模板,并拓展父模板文件中定义的block,形成子模版自身的特有内容。
语法如下:
继承模板:
{% extends 'base.html' %}
定义名为title的block:
{% block title %}
{% endblock %}
包含footer.html模板:
{% include 'footer.html' %}
继承父模板block块中的内容:
{{block.super}}
示例:定义父模板base.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %}
{% endblock %}
</title>
{% block extCss %}
<link href="/static/css/index.css" rel="stylesheet">
{% endblock %}
</head>
<body>
{% block content %}
{% endblock %}
</body>
</html>
父模板一般命名为base.html,它定义了整个网站的“骨架”,而子模版的功能是通过继承父模板并动态地填充父模板中的block,从而形成自己特有的页面内容。
在上述示例中,父模板中定义了3个可以被子模版填充的block,并且在块extCss中引入了static文件夹下的index.css文件。
示例:定义子模版index.html
{% extends 'base.html' %}
{% block title %}
首页
{% endblock %}
{% block content %}
<p>子模版填充父模板中的block</p>
{% endblock %}
在子模版中可以使用{% extends %}标签来继承某个父模板,当继承了父模板后,就可以选择性地定义父模板中的block。
如果在子模版中想要覆盖父模板的块extCss,并引入新的CSS文件,但是并不想将父模板的块extCss中的内容覆盖掉,则可以使用{{block.super}}。
示例:修改上述示例中定义的子模版index.html页面,并修改extCss中的内容
{% extends 'base.html' %}
{% block title %}
首页
{% endblock %}
{% block extCss %}
{{block.super}}
<link href="/static/css/main.css" rel="stylesheet">
{% endblock%}
{% block content %}
<p>子模版填充父模板中的block</p>
{% endblock %}
结论:
- 子模版可以定义父模板中定义的block,并进行内容的填充。
- 子模版可以选择性地覆盖父模板的block,如果没有覆盖父模板中的block,则子模版默认填充父模板block中的内容。
- 子模版可以使用{{block.super}}将父模板中的内容直接继承过来。
7.3 模板中的逻辑表达式
以下是几种常用的逻辑命令:
-
{% for %}:类似Python中的for循环语句,用于循环变量。
for语法1:
{% for 变量 in 列表/元组/字典/字符串 %} {% endfor %}
for语法2:如果列表/元组/字典/字符串参数为空,则执行empty语句。
{% for 变量 in 列表/元组/字典/字符串 %} {% empty %} {% endfor %}
-
{% if %}:类似于Python中的if判断语句,用于判断True还是False。
if语法1:
{% if 表达式 %} {% else %} {% endif %}
if语法2:
{% if 表达式 %} {% endif %}
if语法3:
{% if 表达式 %} {% elif 表达式 %} {% endif %}
-
{{forloop}}:用于循环输出当前循环的次数,一般会嵌套在{% for %}中使用。
{{forloop}}语法:
{{forloop.counter}}:表示当前是第几次循环,从1开始 {{forloop.counter0}}:表示当前是第几次循环,从0开始 {{forloop.revcounter}}:表示当前是第几次循环,倒数开始,到1停 {{forloop.revcounter0}}:表示当前是第几次循环,倒数开始,到0停 {{forloop.first}}:表示是否是第一次循环,如果是第一次循环,则输出为True {{forloop.last}}:表示是否是最后一次循环,如果是最后一次循环,则输出为True
示例:在stus.html中解析所有学生信息
{% extends 'base.html' %} {% block title %} 学生信息页面 {% endblock %} {% block content %} {% for stu in stus %} ID:{{stu.id}} {% if forloop.counter == 1 %} <span style="color:red;"> 学生:{{stu.s_name}} </span> {% else %} <span style="color:yellow;"> 姓名:{{stu.s_name}} </span> {% endif %} {% if stu.s_sex %} 性别:男 {% else %} 性别:女 {% endif %} <br/> {% endfor %} {% endblock %}
该stus.html页面使用了模板继承,继承于base.html,并自定义了block需要动态展示的内容。该模板中使用了变量、模板标签、过滤器。具体分析如下:
- 用两个大括号括起来的参数,称为变量。
- 被大括号和百分号括起来的参数,称为模板标签。在示例代码中包含了if标签、ifequal标签、forloop标签。
7.4 注解
当模板中某行代码或某几行代码需要被屏蔽不执行的时候,应在模板中对代码进行注解,注解方式有以下3种:
- HTML注解:<!–注解内容–>
- 模板中单行注解:{# 注解内容 #}
- 模板中多行注解:{% comment %}多行注解内容{% endcomment %}
示例:HTML注解、单行注解、多行注解的使用:
{% extends 'base.html' %}
{% block title %}
学生信息页面
{% endblock %}
{% block content %}
<!--我是页面内容,我在页面中要展示出来-->
{# 我是隐藏部分,在页面中不允许而且不展示出来 #}
{% comment %}
我是隐藏部分,我不会在页面中展示出来,也不会运行
{% endcomment %}
{% endblock %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
学生信息页面
</title>
<link href="/static/css/index.css" rel="stylesheet">
</head>
<body>
<!--我是页面内容,我在页面中要展示出来-->
</body>
</html>
注意:在<!–注解内容–>进行注解的时候,不能注解模板标签,否者会报模板标签相关的错误提示。而{# 注解内容 #}和{% comment %}注解内容{% endcomment %}可以注解模板标签。
7.5 过滤器
在模板中虽然可以通过变量的输出来实现动态网页的效果,但是这样的 操作不灵活,可以使用过滤器来控制变量显示的格式,使用管道符号“|”来凝结变量和过滤器符号。
语法如下:
变量|过滤器
Django提供了各种各样有用的过滤器来封装Web开发中常见的文本处理工作。例如,字符串的大小写变换、字符串首字母大写、格式化日期、列表截取、字符串长度等。
示例:常见过滤器的使用
<!--1.字符串'Python'转化为大写,输出结果:PYTHON-->
{{'python'|upper}}
<!--2.字符串'PYTHON'转化为小写,输出结果:python-->
{{'PYTHON'|lower}}
<!--3.变量3增加4,输出结果:7-->
{{3|add:'4'}}
<!--4.第一个字符传话成大写形式,输出结果:Python-->
{{'python'|capfirst}}
<!--5.删除指定符号的值,输出结果:studypythonisveryhappy-->
{{'study python is very happy'|cut:' '}}
<!--6.输出缺省值,输出结果:nothing-->
{{''|default:'nothing'}}
<!--7.返回第一个元素,输出结果:p-->
{{'python'|first}}
<!--8.返回最后一个元素,输出结果:n-->
{{'python'|last}}
<!--9.计算长度,输出结果:6-->
{{'python'|length}}
<!--10.随机一个元素,输出随机结果:y-->
{{'python'|random}}
django的内建过滤器介绍如下:
过滤器 | 描述 | 使用形式 |
---|---|---|
add | 将value的值增加2。 | {{value|add:‘2’}} |
addslashes | 在value中的引号前增加反斜线。 | {{value|addslashes}} |
capfirst | 将value的第一个字符转换成大写形式。 | {{value|capfirst}} |
cut | 从给定的value中删除所有arg的值。 | {{value|cut:arg}} |
date | 格式化时间格式。 | {{value|date:“Y-m-d H:M:S”}} |
default | 如果value是False,那么输出使用缺省值。 | {{value|default:“nothing”}} |
default_if_none | 如果value是None,那么输出使用缺省值。 | {{value|default_if_none:“nothing”}} |
dictsort | 如果value是一个字典,那么返回值是按照关键字排序的结果。例如:value是[{‘name’:‘python’},{‘name’:‘java’},{‘name’:‘c++’}],那么输出是[{‘name’:‘c++’},{‘name’:‘java’},{‘name’:‘python’}] | {{value|dictsort:“name”}} |
dictsortreversed | 如果value的值是一个字典,那么返回值是按照关键字排序的结果的反序。 | {{value|dictsortreversed:“name”}} |
divisibleby | 如果value能够被arg整除,那么返回值将是True。例如,value是9,arg是3,那么输出将是True。 | {{value|divisibleby:arg}} |
escape | 替换value中的某些字符,以适应HTML格式。 | {{value|escape}} |
filesizeformat | 格式化value,使其成为易读的文件大小。例如,13KB、4.1MB。 | {{value|filesizeformat}} |
first | 返回列表/字符串中的第一个元素 | {{value|first}} |
iriencode | 如果value中有非ASCII字符,那么将其转化成适合URL的编码,如果value已经进行过URL编码,那该操作不会再起作用。 | {{value|iriencode}} |
join | 使用指定的字符串来连接一个list,作用如同Python中的str.join(list)。例如,value是[‘a’,‘b’,‘c’],arg是"//",那么输出将是a//b//c。 | {{value|join:“arg”}} |
last | 返回列表/字符串中的最后一元素。 | {{value|last}} |
length | 返回value的长度。 | {{value|length}} |
length_is | 如果value的长度等于arg,那么将返回True。例如,value是[‘a’,‘b’,‘c’],arg是3,那么返回True。 | {{value|length_is:“arg”}} |
linebreaks | value中的"\n"将被<br/>替代,并且整个value使用</p>包围起来。 | {{value|linebreaks}} |
linebreaksbr | value中的"\n"将被<br/>替代。 | {{value|linebreaksbr}} |
linenumbers | 显示的文本,带有行数。 | {{value|linenumbers}} |
ljust | 在一个给定宽度的字段中,左对齐显示value。 | {{value|ljust}} |
center | 在一个给定宽度的字段中,中心对齐显示value。 | {{value|center}} |
rjust | 在一个给定宽度的字段中,右对齐显示value。 | {{value|rjust}} |
lower | 将一个字符串转换成小写形式。 | {{value|lower}} |
random | 从给定的list中返回一个任意的Item。 | {{value|random}} |
removetags | 删除value中tag1,tag2…的标签。 | {{value|removetags:“tag1 tag2 tag3…”}} |
safe | 当系统设置autoescaping打开的时候,该过滤器使输出不进行escape转换。 | {{value|safe}} |
safeseq | 与safe基本相同,但safe是针对字符串,而safeseq是针对多个字符串组成的safeseq。 | {{value|safeseq}} |
slice | 与Python语法中的slice相同。 | {{some_list|slice:“2”}} |
striptags | 删除value中的所有HTML标签。 | {{value|striptags}} |
time | 格式化时间输出。 | {{value|time:“H:i”}}或{{value|time}} |
title | 将一个字符串转换成title格式。 | {{value|title}} |
truncatewords | 将value切成truncatewords指定的单词数目。例如,value是Joel is a slug,那么输出就是Joel is。 | {{value|truncatewords:2}} |
upper | 将一个字符串转换成大写形式。 | {{value|upper}} |
urlencode | 将一个字符串进行URL编码。 | {{value|urlencode}} |
wordcount | 返回字符串中单词的数目。 | {{value|wordcount}} |
7.6 反向解析
在6.4重定向redirect小节中,为了避免在视图函数中出现硬编码URL,需要使用命名空间namespace和视图函数对应的URL模式中的name参数。在Django的模板中定义URL反向解析功能与在重定向中定义URL反向解析有不同的调用方式,在重定向中定义URL反向解析使用{% url %}语法,其中参数是可选项。
语法如下:
{% url 'namespace:name' 参数1 参数2 参数3 ... %}
示例:模板中定义URL反向解析
在hello/urls.py中定义总路由
from django.urls import path, include
from app import views
urlpatterns = [
path('app/', include(('app.urls', 'app'), namespace='app/')),
]
在hello/app/urls.py中定义路由
from django.urls import path
from app import views
urlpatterns = [
path(r'student/<int:id>/', views.sel_one_student, name='stu'),
path(r'login/', views.login, name='login'),
]
在stus.html页面中定义URL反向解析地址
{% extends 'base.html' %}
{% block title %}
学生信息页面
{% endblock %}
{% block content %}
<a href="{% url 'app:stu' 1 %}">
查看学生详情地址
</a>
<br>
<a href="{% url 'app:login' %}">
Session案例中定义的URL
</a>
{% endblock %}
在浏览器中输入http://127.0.0.1:8080/all_student/:
- 点击“查看学生详情地址”,模板解析{% url’app:stu’ 1 %}结果为/app/student/1/。如果请求的URL路径中带有参数,则在URL反向解析的时候可以直接在{% url namespace:name 参数 %}中添加参数。
- {% url ‘app:login’ %},模板解析后的结果为/app/login/
本日志所有内容学习自《Python Web开发从入门到精通》(王海飞编著)、网络资源以及本人的调试 ↩︎