第五章 Django框架——模板层Templates
一、MTV模式与MVC模式
二、模板语法之变量
三、模板语法之过滤器filter
四、模板语法之tags(与逻辑相关的)
五、模板之母版继承之block与extends
六、模板之母版导入之include(组件)
七、自定义simpletag
一、MTV模式与MVC模式
MVC模式
MVC,全名是Model View Controller,是软件工程中的一种软件架构模式,把软件系统分为三个基本部分:模型(Model)、视图(View)和控制器(Controller),具有耦合性低、重用性高、生命周期成本低等优点。
Django的MTV模式
Django框架的设计模式借鉴了MVC框架的思想,也是分成三部分,来降低各个部分之间的耦合性。
Django框架的不同之处在于它拆分的三部分为:Model(模型)、Template(模板)和View(视图),也就是MTV框架。
- Model(模型):负责业务对象与数据库的对象(ORM)
- Template(模版):负责如何把页面展示给用户
- View(视图):负责业务逻辑,并在适当的时候调用Model和Template
- 此外,Django还有一个urls分发器,它的作用是将一个个URL的页面请求分发给不同的view处理,view再调用相应的Model和Template
二、模板语法之变量
只需要记两种特殊符号:
{
{ filter }}和 {% tag %}变量相关的用{
{}},逻辑相关的用{%%}。1.变量
语法:
{
{ 变量名 }}构成:
变量名由字母数字和下划线组成。
点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。
基本使用:
注意:
如果页面输入一个没有赋值的变量,页面上将不会显示它
方法:
A)列表操作
①按索引去列表值
B)字典操作
①按key取值
C)对象操作
①直接调用对象(也可以用__str__方法控制打印格式)
结果:
②获取对象属性
③获取对象方法(只能调用不带参数的方法,因为没有办法加括号)
三、模板语法之过滤器filter
语法:
{
{ value|filter_name:参数 }}切记:
'|'左右没有空格没有空格没有空格
方法:
①default 如果value值没传的话就显示default的内容
# 如果value值没传的话就显示nothing{ { value|default: "nothing"}}
②length 返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.
{
{ name|length }}
③filesizeformat 将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB'
, '4.1 MB'
, '102 bytes'
, 等等)。
{ { value|filesizeformat }}
④slice 切片 可以切列表,字符串
{ {value|slice:"2:-1"}}
⑤date 格式化时间
{ { value|date:"Y-m-d H:i:s"}}
⑥safe 告诉浏览器我这段代码是完全安全的
Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。
比如:
value = "<a href='#'>点我</a>"
{ { value|safe}}
⑦truncatechars 如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾
参数:截断的字符数
{ { value|truncatechars:9}}
⑧trunctewords 将字符串转换为省略表达式
{ 'This is a pen' | truncatewords:2 }}返回
This is ...⑨其他(了解即可)
过滤器 | 描述 | 示例 |
upper | 以大写方式输出 | { { user.name | upper }} |
add | 给value加上一个数值 | { { user.age | add:”5” }} |
addslashes | 单引号加上转义号 | |
capfirst | 第一个字母大写 | { { ‘good’| capfirst }} 返回”Good” |
center | 输出指定长度的字符串,把变量居中 | { { “abcd”| center:”50” }} |
cut | 删除指定字符串 | { { “You are not a Englishman” | cut:”not” }} |
date | 格式化日期 | |
default | 如果值不存在,则使用默认值代替 | { { value | default:”(N/A)” }} |
default_if_none | 如果值为None, 则使用默认值代替 | |
dictsort | 按某字段排序,变量必须是一个dictionary | {% for moment in moments | dictsort:”id” %} |
dictsortreversed | 按某字段倒序排序,变量必须是dictionary | |
divisibleby | 判断是否可以被数字整除 | { { 224 | divisibleby:2 }} 返回 True |
escape | 按HTML转义,比如将”<”转换为”<” | |
filesizeformat | 增加数字的可读性,转换结果为13KB,89MB,3Bytes等 | { { 1024 | filesizeformat }} 返回 1.0KB |
first | 返回列表的第1个元素,变量必须是一个列表 | |
floatformat | 转换为指定精度的小数,默认保留1位小数 | { { 3.1415926 | floatformat:3 }} 返回 3.142 四舍五入 |
get_digit | 从个位数开始截取指定位置的数字 | { { 123456 | get_digit:’1’}} |
join | 用指定分隔符连接列表 | { { [‘abc’,’45’] | join:’*’ }} 返回 abc*45 |
length | 返回列表中元素的个数或字符串长度 | |
length_is | 检查列表,字符串长度是否符合指定的值 | { { ‘hello’| length_is:’3’ }} |
linebreaks | 用<p>或<br>标签包裹变量 | { { “Hi\n\nDavid”|linebreaks }} 返回<p>Hi</p><p>David</p> |
linebreaksbr | 用<br/>标签代替换行符 | |
linenumbers | 为变量中的每一行加上行号 | |
ljust | 输出指定长度的字符串,变量左对齐 | { {‘ab’|ljust:5}}返回 ‘ab ’ |
lower | 字符串变小写 | |
make_list | 将字符串转换为列表 | |
pluralize | 根据数字确定是否输出英文复数符号 | |
random | 返回列表的随机一项 | |
removetags | 删除字符串中指定的HTML标记 | { {value | removetags: “h1 h2”}} |
rjust | 输出指定长度的字符串,变量右对齐 | |
slice | 切片操作, 返回列表 | { {[3,9,1] | slice:’:2’}} 返回 [3,9]{ { 'asdikfjhihgie' | slice:':5' }} 返回 ‘asdik’ |
slugify | 在字符串中留下减号和下划线,其它符号删除,空格用减号替换 | { { '5-2=3and5 2=3' | slugify }} 返回 5-23and5-23 |
stringformat | 字符串格式化,语法同python | |
time | 返回日期的时间部分 | |
timesince | 以“到现在为止过了多长时间”显示时间变量 | 结果可能为 45days, 3 hours |
timeuntil | 以“从现在开始到时间变量”还有多长时间显示时间变量 | |
title | 每个单词首字母大写 | |
truncatewords | 将字符串转换为省略表达方式 | { { 'This is a pen' | truncatewords:2 }}返回 This is ... |
truncatewords_html | 同上,但保留其中的HTML标签 | { { '
|
urlencode | 将字符串中的特殊字符转换为url兼容表达方式 | { { ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}} |
urlize | 将变量字符串中的url由纯文本变为链接 | |
wordcount | 返回变量字符串中的单词数 | |
yesno | 将布尔变量转换为字符串yes, no 或maybe | { { True | yesno }} { { False | yesno }} { { None | yesno }} 返回 yes no maybe |
自定义filter:
自定义过滤器只是带有一个或两个参数的Python函数:
- 变量(输入)的值 - -不一定是一个字符串
- 参数的值 - 这可以有一个默认值,或完全省略
例如,在过滤器{
{var | foo:“bar”}}中,过滤器foo将传递变量var和参数“bar”。自定义filter代码文件摆放位置:
app01/ __init__.py models.py templatetags/ # 在app01下面新建一个package package __init__.py app01_filters.py # 建一个存放自定义filter的文件 views.py
编写自定义filter:
from django import templateregister = template.Library()@register.filter(name="cut")def cut(value, arg): return value.replace(arg, "")@register.filter(name="addSB")def add_sb(value): return "{} SB".format(value)
使用自定义filter:
{ # 先导入我们自定义filter那个文件 #}{% load app01_filters %}{ # 使用我们自定义的filter #}{ { somevariable|cut:"0" }}{ { d.name|addSB }}
四、模板语法之tags(与逻辑相关的)
1.for
语法:
①for循环的基本用法:
{% for i in name_list %}{ { i }}{% endfor %}{% for i in name_list %}{ { i }}{% empty %}空空如也{% endfor %} ②for循环可用的属性:forloop代表当前的for循环
forloop.counter forloop.counter表示当前循环的执行次数的整数计数器。该计数器从1开始,即第一次循环时{ {% forloop.counter %}}
的值为1 forloop.counter0 forloop.counter0 计数从0开始,第一次循环其值为0
forloop.revcounter 值是一个整数,表示循环中剩余的元素数量。第一次循环时, for-loop.revcounter 的值是序列中要遍历的元素总数。最后一次循环时, forloop.revcounter 的值为 1
forloop.revcounter0 索引是基于零的。第一次循环时, for-loop.revcounter0 的值是序列中元素数量减去一。最后一次循环时, forloop.revcounter0 的值为 0
forloop.first 是个bool值,第一次循环时为true
forloop.last 是个bool值,最后一次循环时为trueforloop.parentloop forloop.parentloop 引用父级循环的 forloop 对象举例:
{% 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>{% endfor %}</table>{% endfor %}
③for...empty...
- { % for user in user_list %}
- { { user.name }} { % empty %}
- 空空如也 { % endfor %}
2.if,elif,else
语法:
{% if a > b %}
{% endif %}{% if a > b %}{% else %}{% endif %}{% if a > b %}{% elif %}{% else %}{% endif %}if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
3.with
定义一个中间变量
{% with total=business.employees.count %} { { total }} employee{ { total|pluralize }}{ % endwith %}
自定义tags
自定义tags代码文件摆放位置:
编写自定义tags:
使用自定义tags:
小技巧:
static引入
注意:
①filter可以用在if等语句后,simple_tag不可以
{% if num|filter_multi:30 > 100 %} { { num|filter_multi:30 }}{ % endif %}
②注意事项
Django的模板语言不支持连续判断,即不支持以下写法:
{% if a > b > c %}...{ % endif %}
③Django的模板语言中属性的优先级大于方法
def xx(request): d = { "a": 1, "b": 2, "c": 3, "items": "100"} return render(request, "xx.html", { "data": d})
如上,我们在使用render方法渲染一个页面的时候,传的字典d有一个key是items并且还有默认的 d.items() 方法,此时在模板语言中:
{ { data.items }}
默认会取d的items key的值。
五、模板之母版继承之block与extends
为什么要有母版(why):
可以将每个页面共有的部分定义为母版使用,多个页面公用的部分提取出来,放在一个 母版 里面,其他的页面只需要 继承 母版就可以了。
1.具体使用的步骤:
① 把公用的HTML部分提取出来,放到base.html文件中②在base.html中,通过定义block,把每个页面不同的部分区分出来{% block page-main %}...{ % endblock%}
{% extends 'xxx.html' %}
④然后block名去指定替换母版中相应的位置
2.母版的继承
在子页面中在页面最上方使用下面的语法来继承母板。
{% extends 'layouts.html' %}
3.母版的导入
语法:{% include '模版名称' %}
如:{% include 'adv.html' %}
使用母版继承的注意事项:
①{% extends 'base.html' %} --> 母版文件:base.html要加引号
②{% extends 'base.html' %}必须放在子页面的第一行!!!③可以在base.html中定义很多block,通常我们会额外定义page-css和page-js两个块④view.py相应的函数中返回的是对应的子页面文件不是base.html④view.py相应的函数中返回的是对应的子页面文件不是base.html
④view.py相应的函数中返回的是对应的子页面文件不是base.html
重要的事情说三遍
静态文件相关:
用法一:{% static "xxx.css" %}
引用图片
{% load static %}
引入Js
{% load static %}
某个文件多处被用到可以存为一个变量
% load static %}{ % static "images/hi.jpg" as myphoto %}
用法二 :使用get_static_prefix
{% load static %}
{% load static %}{ % get_static_prefix as STATIC_PREFIX %}
六、模板之母版导入之include(组件)
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
{% include 'navbar.html' %}
七、自定义simpletag
①先去setting里面把app名字配置上
②再app目录下创建一个templatetags模块③写py文件(my_test.py)from django import templateregister=template.Library()@register.inclusion_tag('test.html')def my_inclusion(n): data=[] for i in range(n): data.append('第%s行'%i) return { 'data':data}
④写test.html页面
- { % for choice in data %}
- { { choice }} { % endfor %}
⑤{% load my_test %}
⑥{% my_inclusion 10 %} 它会返回html的页面
inclusion_tag
多用于返回html代码片段
示例:
templatetags/my_inclusion.py
from django import templateregister = template.Library()@register.inclusion_tag('result.html')def show_results(n): n = 1 if n < 1 else int(n) data = ["第{}项".format(i) for i in range(1, n+1)] return { "data": data}
templates/snippets/result.html
inclusion_tag test { % load inclusion_tag_test %}{ % show_results 10 %}