在Django框架中,模板时可以帮助开发者快速生成呈现给用户页面的工具。
模板的设计方式实现了我们MVT中VT的解耦(M:Model,V:View,T:Tempalates),VT有着N:M的关系,一个V可以调用任何T,一个T可以供任意V使用。
模板的处理可以分为两个过程:
模板主要有两部分:
模板中的动态代码段除了做基本的静态填充,还可以实现一些基本运算、转换和逻辑。
静态页面:页面数据是本地固定的
动态页面:页面数据来源于后台服务器
模板中的变量:视图函数传递给模板的数据,遵守标识符规则
模板中的列表
使用索引,不允许负索引
items = [‘apples’,‘bananas’,‘carrots’]
{{ items.2 }}
模板中的标签
模板中的if语句:
{% if today_is_weekend %}
<p>Welcome to the weekend.p>
{% endif%}
{% if athlete_list and coach_list %}
<p>Both athletes and coachs are avaliable.p>
{% endif %}
{% if not athlete_list %}
<p>There are not athletes.p>2
{% endif %}
{% if athlete_list or coach_list %}
<p>There are some athletes or some coachs.p>
{% endif %}
{% if 'bc' in 'abcdef'%}
This appears since 'bc' is a substring of 'abcdef'
{% endif %}
{% if user not in users%}
If users is a list,this will not appear if user isn't an element of the list.
{% endif %}
模板中的for语句:
格式
{% for 变量 in 列表%}
语句1
{% empty %}
语句2
{% endfor %}
当列表为空或者不存在时,执行empty之后的语句。
{{ forloop.counter }} 表示当前是第几次循环,从1开始数
{% for item in todo_list %}
<p>{{ forloop.counter }}:{{ item }}p>
{% endfor %}
```
{{ forloop.counter0 }} 表示当前是第几次循环,从0开始数
{{ forloop.revcounter }}表示当前是第几次循环,倒着数,到1停
{{ forloop.revcounter0 }}表示当前是第几次循环,倒着数,到0停
{{ forloop.first }} 是否是第一个( 布尔值True或者False)
```html
{% for object in objects %}
{% if forloop.first %}
<li class="first">
{% else %}
<li>
{% endif %}
{{ object }}li>
{% endfor %}
{{ forloop.last }} 是否是最后一个( 布尔值True或者False)
{% for link in links %}
{{ link }}{% if not loop.last %} | {% endif %}
{% endfor %}
forloop.parentloop
{% for country in countries %}
<table>
{% for city in country.city_list %}
<tr>
<td>Country #{{ forloop.parentloop.counter }}td>
<td>City #{{ forloop.counter }}td>
<td>{{ city }}td>
tr>
table>
{% endfor %}
注释:
过滤器
{{ var|过滤器 }}
作用:在变量显示前修改
add {{ var|add:2}}
没有减法过滤器,但是加法里可以加负数
{{ var|add:-2}}
lower(将字母变成小写字母)
{{ name|lower }}
upper(将字母变成大写字母)
{{ my_list|first|upper }}
截断
{{ bio|truncatechars:30 }}
过滤器可以传递参数,参数需要使用引号引起来
比如join:{{ students|join:‘=’ }}
默认值:default,格式{{ var|default:value}}
如果变量没有被提供或者为False、空,会使用默认值。
根据指定格式转换日期为字符串,处理时间的,就是针对date进行的转换
{{ dateVal | date:‘y-m’d’ }}
HTML转义
将接收到的数据当成普通字符串处理还是当成HTML代码来渲染的一个问题。
模板继承
block:
{% block XXX %}
code
{% endblock %}
extends继承,写在开头位置
{% extends ‘父模板路径’ %}
include:加载模板进行渲染
{% include ’ 模板文件’ %}
{{ block.super }}:获取父模板中block中的内容
首先定义一个用于测试的视图函数:
render中传递的数据必须是字典格式,data是字典格式,所以可以直接将data传递过去。如果不是字典类型的数据,如data=[1,2,3],那么在传递数据时需要写成字典格式,即该数据作为value,还要给它一个key,{‘data’:data}。
# 模板测试函数
def model_test(request):
data = {
'name':'zhangsan',
'age':30,
'likes':['movie','game','code'],
'address':{'city':'深圳','province':'广东'},
'stars':[
['周杰伦','林俊杰','王力宏','伍佰'],
['张韶涵','张靓颖','杨丞琳','萨顶顶'],
['李荣浩','薛之谦','许嵩','汪苏泷']
],
}
# render传给模板的数据是一个字典,data是一个字典
return render(request,'modeltest.html',data)
在跟路由下写上其路径:
path('modeltest/',model_test),
模板文件modeltest.html:
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django模板title>
head>
<body>
<h2>Django模板h2>
<hr>
{# 单行注释 #}
{% comment %}
多行注释
多行注释内容
{% endcomment %}
{# 变量的使用 #}
<p>name:{{ name }}p>
<p>age:{{ age }}p>
<p>likes:{{ likes }}p>
<p>likes.2:{{ likes.2 }}p>
<p>address:{{ address }}p>
<p>address.city:{{ address.city}}p>
<p>address.province:{{ address.province }}p>
<hr>
body>
html>
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django模板title>
head>
<body>
<h2>Django模板h2>
<hr>
{# 单行注释 #}
{% comment %}
多行注释
多行注释内容
{% endcomment %}
{# 变量的使用 #}
<p>name:{{ name }}p>
<p>age:{{ age }}p>
<p>likes:{{ likes }}p>
<p>likes.2:{{ likes.2 }}p>
<p>address:{{ address }}p>
<p>address.city:{{ address.city}}p>
<p>address.province:{{ address.province }}p>
<hr>
{# 标签 #}
<h2>if语句h2>
<h4>单分支if语句h4>
{% if age >= 18 %}
<p>{{ name }} 已经成年p>
{% endif %}
<h4>双分支if语句h4>
{% if age >= 18 %}
<p>{{ name }} 已经成年p>
{% else %}
<p>{{ name }} 未成年p>
{% endif %}
<h4>多分支if语句h4>
{% if age < 18 %}
<p>{{ name }} 未成年p>
{% elif age < 60 %}
<p>{{ name }} 是壮年p>
{% else %}
<p>{{ name }} 是老年p>
{% endif %}
<h4>结合运算符h4>
{% if age >= 18 and age <= 60 %}
<p>{{ name }} 是壮年,风华正茂p>
{% endif %}
{% if age < 18 or age > 60 %}
<p>{{ name }} 是未成年或者老年人p>
{% endif %}
{# in和not in #}
{% if 'movie' in likes %}
<p>{{ name }} 喜欢moviep>
{% endif %}
{# br标签可以给页面添加滚动栏 #}
<br><br><br><br><br><br>
<br><br><br><br><br><br>
<br><br><br><br><br><br>
body>
html>
forloop表示当前循环,forloop.parentloop表示当前循环的父循环,即当前循环的上一层循环。
<hr>
<h3>for循环语句h3>
{% for like in likes %}
<p>爱好:{{ like }}p>
{% endfor %}
页面效果:
for循环中empty的用法:如果被遍历的数据容器是空的或者无法被遍历的,就不会执行for循环中的语句。
likes2并不存在,所以就会执行empty下的语句。
<h4>empty的用法:如果被遍历的数据容器是空的或者无法被遍历的,就不会执行for循环中的语句h4>
{% for like in likes2 %}
<p>爱好:{{ like }}p>
{% empty %}
<p>likes2为空或者不存在p>
{% endfor %}
for循环语句中下标的使用,counter0表示每一条循环语句的下标从0开始数;counter表示每一条循环语句的下标从1开始数;revcounter0表示每一条循环语句的下标倒着数,到0结束,即最后一条循环语句的下标是0;revcounter表示每一条循环语句的下标倒着数,到1结束,即最后一条循环语句的下标是1。
.first 会标记出循环语句第一次执行的结果,.last会标记出循环语句最后一次执行的结果。
<h4>下标h4>
{% for like in likes %}
<p>
counter0:{{ forloop.counter0 }},
counter:{{ forloop.counter }},
revcounter0:{{ forloop.revcounter0 }},
revcounter:{{ forloop.revcounter }},
{# 判断是否是第一条循环语句和判断是否是最后一条循环语句#}
{% if forloop.first %}
<b> - first b>
{% endif %}
{% if forloop.last %}
<b> - last b>
{% endif %}
p>
{% endfor %}
嵌套循环:
for循环语句中可以嵌套for循环,也可以嵌套if语句。通过嵌套循环和表格来展示嵌套列表stars中的数据。table标签表示创建一个表格,其样式可以通过标签属性来设置。tr标签表示表格的每一行,td标签表示每一个单元格。通过嵌套循环遍历表格的每一行,再遍历每一行中的每一个单元格。
<h4>循环嵌套h4>
{# 表格标签table,border显示表格边框,宽度width为300 #}
<table border="1" width="300">
{# 遍历表格的每一行,每一个tr标签表示表格的一行 #}
{% for star in stars %}
<tr>
{# 遍历表格一行的每一个单元格,td标签表示一个单元格 #}
{% for s in star %}
<td>
{{ s }}
td>
{% endfor %}
tr>
{% endfor %}
table>
<h4>循环嵌套h4>
{# 表格标签table,border显示表格边框,宽度width为300 #}
<table border="1" width="500">
{# 遍历表格的每一行,每一个tr标签表示表格的一行 #}
{% for star in stars %}
<tr>
{# 遍历表格一行的每一个单元格,td标签表示一个单元格 #}
{% for s in star %}
<td>
{{ s }} -
{# forloop表示当前循环,parentloop表示父循环,forloop.parentloop表示当前循环的父循环,即上一层循环 #}
{# counter表示从1开始数的下标,即给上一层循环的每一循环都添加下标,从1开始数 #}
{{ forloop.parentloop.counter }}
td>
{% endfor %}
tr>
{% endfor %}
table>
页面效果:
forloop.counter表示当前循环的下标,从1开始数,当前循环遍历一行的每一个单元格。
{% for s in star %}
<td>
{{ s }} -
{# forloop表示当前循环,parentloop表示父循环,forloop.parentloop表示当前循环的父循环,即上一层循环 #}
{# counter表示从1开始数的下标,即给上一层循环的每一循环都添加下标,从1开始数 #}
{{ forloop.parentloop.counter }} -
{{ forloop.counter }}
td>
{% endfor %}
页面效果:
第一个数字表示第一层循环的下标,第二个数字表示第二层循环的下标。
使用过滤器进行运算:
<hr>
<h4>过滤器h4>
<p>age = {{ age }}p>
{# 使用过滤器进行加法:add表示+ #}
<p>age = {{ age | add:2 }}p>
{# 若是要进行减法,可以加上负数 #}
<p>age = {{ age | add:-2 }}p>
<p>name = {{ name }}p>
{# 将名字的第一个字母变成大写 #}
<p>name|first|upper = {{ name|first|upper }}p>
{# 将名字中的字母都变成大写 #}
<p>name|upper = {{ name|upper }}p>
{# 截断字符串 #}
<p>name|truncatechars:4 = {{ name|truncatechars:4 }}p>
{# 字符串拼接 #}
<p>likes = {{ likes }}p>
<p>likes|join:'+'= {{ likes|join:'+' }}p>
页面效果:
显示日期:
在视图函数model_test()的data中添加:
'dt':datetime.datetime.now(),
模板文件中:
{# 显示日期 #}
<p>dt = {{ dt }}p>
<p>dt = {{ dt|date:'y-m-d' }}p>
<p>dt = {{ dt|date:'Y-m-d' }}p>
页面效果:
y-m-d中,y表示年份的后两位数字,m表示月份,d表示天。大写Y可以显示完整的年份。
HTML转义:
必须确保是安全的HTML标签才能使用safe进行解析。
在视图函数model_test()的data中添加:
# b标签表示加粗字体
'code':'I am a people',
模板文件中:
{# HTML转义 #}
<p>code = {{ code }}p>
<p>code|safe = {{ code|safe }}p>
{# 模板继承 #}
{# block方法是写在父模板中,block.super用于获取父模板中block的内容 #}
{# extend方法是写在子模板的开头位置,用来继承父模板 #}
{# include方法用于在模板中引入其他的模板文件 #}
创建视图函数:
# 模板继承视图函数
# 父模板
def block(request):
return render(request,'block.html')
# 子模板
def child(request):
return render(request,'child.html')
路由url:
path('block/', block),
path('child/', child),
模板:
block标签中的内容并不会在网页中显示。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
{# css #}
{% block extcss %}
{% endblock %}
head>
<body>
<h2>父模板h2>
<hr>
{% block head %}
{% endblock %}
<hr>
{% block content %}
<button>我是父模板中的按钮Contentbutton>
{% endblock %}
<hr>
{% block foot %}
{% endblock %}
<hr>
{# JavaScript #}
{% block extjs %}
{% endblock %}
body>
html>
子模板中不需要写head、body标签这些固定的东西。只需要使用block继承父模板就可以获得和父模板中一样的内容。但是,子模板的block标签中的内容默认会覆盖父模板中block标签的内容。比如在父模板content中的按钮并不会在子模板页面中显示,如果想要继承父模板block标签中的内容,需要使用block.super。
{# 子模板中不需要写这些固定的东西 #}
{# 继承父模板 #}
{# 继承之后子模板中的内容与父模板中内容一样 #}
{% extends 'block.html' %}
{% block head %}
<div>
<button>headbutton>
div>
{% endblock %}
{% block content %}
{# 默认情况下,子模板会覆盖父模板的内容。如果想将父模板中block内容继承,则需要使用block.super #}
{{ block.super }}
<div>
<button>contentbutton>
div>
{% endblock %}
{% block foot %}
<div>
<button>footbutton>
div>
{% endblock %}
使用include方法导入其他模板中的内容。如果模板中内容太多,会显得杂乱,我们可以将部分内容放到其他模板文件中,使用时再用include方法从其他模板中导入。
创建一个child_include.html:
<ol>
<li>床前明月光,疑是地上霜li>
<li>黑云压城城欲摧,甲光向日金鳞开li>
<li>沉舟侧畔千帆过,病树前头万木春li>
<li>长风破浪会有时,直挂云帆济沧海li>
ol>
在child.html中使用include方法引用child_include.html中的内容:
{% block foot %}
<div>
<button>footbutton>
div>
{% 导入其他模板文件 %}
{% include 'child_include.html' %}
{% endblock %}
渲染render,利用的是模板语言,可以将变量、数据传进去,并且html内部可以使用大量的模板语法。渲染的作用就是将后端和前端绑定在一起。使用模板(HTML+模板语言)——前后端不分离