Django模板Templates
一、模板templates介绍
在Django框架中,模板时可以帮助开发者快速生成呈现给用户页面的工具。
模板的设计方式实现了我们MVT中VT的解耦(M:Model,V:View,T:Tempalates),VT有着N:M的关系,一个V可以调用任何T,一个T可以供任意V使用。
模板的处理可以分为两个过程:
- 加载HTML
- 渲染数据 render()
模板主要有两部分:
- HTML静态代码
- 模板语言,动态插入的代码段(挖坑、填坑) {{ var }}
模板中的动态代码段除了做基本的静态填充,还可以实现一些基本运算、转换和逻辑。
静态页面:页面数据是本地固定的
动态页面:页面数据来源于后台服务器
模板中的变量:视图函数传递给模板的数据,遵守标识符规则
- 语法:{{ var }} ,如果变量不存在,则插入空字符串。
- 方法不能有参数(方法后不能加小括号)
{{ str }}
{{ str.upper }}
{{ str.isdigit }}
{{ dict.key }}
模板中的列表
使用索引,不允许负索引
items = [‘apples’,‘bananas’,‘carrots’]
{{ items.2 }}
模板中的标签
- 语法:{% tag %}
- 作用:
1.加载外部传入的变量
2.在输出中创建文本
3.控制循环或逻辑
模板中的if语句:
- 格式:
- if 单分支
{% if 表达式 %}
语句
{% endif %} - if双分支
{% if 表达式 %}
语句
{% else %}
语句
{% endif %} - if多分支
{% if 表达式 %}
语句
{% elif 表达式%}
语句
{% else %}
语句
{% endif %}
- if 单分支
- 判断true或false
{% if today_is_weekend %}
<p>Welcome to the weekend.</p>
{% endif%}
- 使用and or not
{% 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 %}
- 使用 in 和 not in
{% 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 %}
-
注释:
- 单行注释
{# 被注释的内容 #} - 多行注释
{% comment %}
内容
{% endcomment %}
- 单行注释
-
过滤器
{{ 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代码来渲染的一个问题。- 渲染成HTML:
{{ code|safe }} - 关闭自动转义
{% autoescape off %}
code
{% endautoescape %} - 打开自动转义
{% autoescape on %}
code
{% endautoescape %}
- 渲染成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>
访问页面:
三、模板语法——标签
3.1 if语句
<!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 }} 喜欢movie</p>
{% endif %}
{# br标签可以给页面添加滚动栏 #}
<br><br><br><br><br><br>
<br><br><br><br><br><br>
<br><br><br><br><br><br>
</body>
</html>
3.2 for语句
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':'<b>I am a people</b>',
模板文件中:
{# HTML转义 #}
<p>code = {{ code }}</p>
<p>code|safe = {{ code|safe }}</p>
页面效果:
b标签被解析,标签中的文本被加粗。
五、模板语法——继承
{# 模板继承 #}
{# 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标签中的内容并不会在网页中显示。
- block.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{# css #}
{% block extcss %}
{% endblock %}
</head>
<body>
<h2>父模板</h2>
<hr>
{% block head %}
{% endblock %}
<hr>
{% block content %}
<button>我是父模板中的按钮Content</button>
{% endblock %}
<hr>
{% block foot %}
{% endblock %}
<hr>
{# JavaScript #}
{% block extjs %}
{% endblock %}
</body>
</html>
页面效果:
- child.html:
子模板中不需要写head、body标签这些固定的东西。只需要使用block继承父模板就可以获得和父模板中一样的内容。但是,子模板的block标签中的内容默认会覆盖父模板中block标签的内容。比如在父模板content中的按钮并不会在子模板页面中显示,如果想要继承父模板block标签中的内容,需要使用block.super。
{# 子模板中不需要写这些固定的东西 #}
{# 继承父模板 #}
{# 继承之后子模板中的内容与父模板中内容一样 #}
{% extends 'block.html' %}
{% block head %}
<div>
<button>head</button>
</div>
{% endblock %}
{% block content %}
{# 默认情况下,子模板会覆盖父模板的内容。如果想将父模板中block内容继承,则需要使用block.super #}
{{ block.super }}
<div>
<button>content</button>
</div>
{% endblock %}
{% block foot %}
<div>
<button>foot</button>
</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>foot</button>
</div>
{% 导入其他模板文件 %}
{% include 'child_include.html' %}
{% endblock %}
页面效果:
渲染render,利用的是模板语言,可以将变量、数据传进去,并且html内部可以使用大量的模板语法。渲染的作用就是将后端和前端绑定在一起。使用模板(HTML+模板语言)——前后端不分离