05django模板层
目的
将页面的设计和Python的代码分离开会更干净简洁更容易维护
核心内容
- 变量 {{var_name}}
- 标签
变量 {{ var_name }}
1.变量的使用
首先新建一个html5的页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>{{ msg }}</p>
<p>{{ dic }}</p>
<p>{{ obj }}</p>
<p>{{ li }}</p>
</body>
</html>
在view中添加代码
from django.shortcuts import render
def test(request):
# 传给模板的变量值可以是任意python类型,如下
msg='hello world'
dic={'k1':1,'k2':2}
class Person(object):
def __init__(self,name,age):
self.name=name
self.age=age
obj=Person('egon',18)
li = [1,'aaa',obj]
return render(request,'test.html',{'msg':msg,'dic':dic,'obj':obj,'li':li})
# 注意:
# 1、render函数的第三个参数包含了要传给模板的变量值,是一个字典类型,该字典中的key必须与模板文件中的变量名相对应,
# render函数会去templates目录下找到模板文件,然后根据字典中的key对应到模板文件中的变量名进行赋值操作,最后将赋值后的模板文件内容返回给浏览器
# 2、可以将render函数的第三个参数简写为locals(),如下
return render(request,'test.html',locals()) #locals()会将函数test内定义的名字与值转换为字典中的k与v
总结:
Django模板中. 有特殊的意义
list: 按list.index取值,注意不能用python原始取值方法list[0]
取list中的第一个参数
{{ list.0 }}
取字典中key的值
{{ d.name }}
取对象的name属性
{{ person_list.0.name }}
.操作只能调用不带参数的方法
{{ person_list.0.dream }}
调用字符串对象的upper方法,注意不要加括号
{{ msg.upper }}
取对象的name属性
{{ obj.name }}
取列表的第2个元素,然后变成大写
{{ li.1.upper }}
取列表的第3个元素,并取该元素的age属性
{{ li.2.age }}
过滤器
DJANGO模板自带了很多的过滤器,详细介绍:
https://docs.djangoproject.com/zh-hans/2.2/ref/templates/builtins/
语法
{{obj|filter__name:param}}
常用的过滤器
default
{{ value|default:"nothing"}}
如果value值没传的话就显示nothing
注:TEMPLATES的OPTIONS可以增加一个选项:string_if_invalid:'找不到',可以替代default的的作用。
filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 KB', '4.1 MB', '102 bytes', 等等)。例如:
{{ value|filesizeformat }}
如果 value 是 123456789,输出将会是 117.7 MB。
add
给变量加参数
{{ value|add:"2" }}
value是数字4,则输出结果为6。
{{ first|add:second }}
如果first是 [1,.2,3] ,second是 [4,5,6] ,那输出结果是 [1,2,3,4,5,6] 。
lower upper
小写
{{ value|lower }}
大写
{{ value|upper}}
title
标题
{{ value|title }}
ljust
左对齐
"{{ value|ljust:"10" }}"
rjust
右对齐
"{{ value|rjust:"10" }}"
center
居中
"{{ value|center:"15" }}"
length
{{ value|length }}
返回value的长度,如 value=['a', 'b', 'c', 'd']的话,就显示4.
slice
切片
{{value|slice:"2:-1"}}
first
取第一个元素
{{ value|first }}
last
取最后一个元素
{{ value|last }}
join
使用字符串拼接列表。同python的str.join(list)。
{{ value|join:" // " }}
truncatechars
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾。
参数:截断的字符数
{{ value|truncatechars:9}}
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}}
3.标签
3.1 for 标签
#1、遍历每一个元素:
{% for person in person_list %}
<p>{{ person.name }}</p>
{% endfor %}
#2、可以利用{% for obj in list reversed %}反向循环。
#3、遍历一个字典:
{% for key,val in dic.items %}
<p>{{ key }}:{{ val }}</p>
{% endfor %}
#4、循环序号可以通过{{ forloop }}显示
forloop.counter 当前循环的索引值(从1开始)
forloop.counter0 当前循环的索引值(从0开始)
forloop.revcounter 当前循环的倒序索引值(从1开始)
forloop.revcounter0 当前循环的倒序索引值(从0开始)
forloop.first 当前循环是第一次循环则返回True,否则返回False
forloop.last 当前循环是最后一次循环则返回True,否则返回False
forloop.parentloop 本层循环的外层循环
#5、for标签可以带有一个可选的{% empty %} 从句,在变量person_list为空或者没有被找到时,则执行empty子句
{% for person in person_list %}
<p>{{ person.name }}</p>
{% empty %}
<p>sorry,no person here</p>
{% endfor %}
3.2 if 标签
# 1、注意:
{% if 条件 %}条件为真时if的子句才会生效,条件也可以是一个变量,if会对变量进行求值,
在变量值为空、或者视图没有为其传值的情况下均为False
# 2、具体语法
{% if num > 100 or num < 0 %}
<p>无效</p>
{% elif num > 80 and num < 100 %}
<p>优秀</p>
{% else %}
<p>凑活吧</p>
{% endif %}
#3、if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
3.3 with 标签
# with标签用来为一个复杂的变量名起别名,如果变量的值来自于数据库,
# 在起别名后只需要使用别名即可,无需每次都向数据库发送请求来重新获取变量的值
{% with li.1.upper as v %}
{{ v }}
{% endwith %}
3.4 csrf_token 标签
# 当用form表单提交POST请求时必须加上标签{% csrf_token%},该标签用于防止跨站伪造请求
<form action="" method="POST">
{% csrf_token %}
<p>用户名:<input type="text" name="name"></p>
<p>密码:<input type="password" name="pwd"></p>
<p><input type="submit" value="提交"></p>
</form>
# 具体工作原理为:
# 1、在GET请求到form表单时,标签{% csrf_token%}会被渲染成一个隐藏的input标签,
#该标签包含了由服务端生成的一串随机字符串,如<input type="hidden" name="csrfmiddlewaretoken" value="dmje28mFo...OvnZ5">
# 2、在使用form表单提交POST请求时,会提交上述随机字符串,服务端在接收到该POST请求时会对比该随机字符串,
# 对比成功则处理该POST请求,否则拒绝,以此来确定客户端的身份
3.5 注释标签
# 单行注释
{# #}
# 多行注释
{% comment "Optional note" %}
<p>Commented out text with {{ create_date|date:"c" }}</p>
{% endcomment %}
4. 自定义过滤器和标签
1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
2、在app中创建templatetags模块(模块名只能是templatetags)
3、创建任意 .py 文件,如:my_tags.py
#my_tags.py
from django import template
register = template.Library() # 注意变量名必须为register,不可改变
#1、自定义过滤器
@register.filter
def my_multi_filter(v1 ,v2): # 自定义的过滤器只能定义最多两个参数,针对{{ value1 | filter_multi:value2 }},参数传递为v1=value1,v2=value2
return v1 * v2
#2、自定义标签
@register.simple_tag
def my_multi_tag(v1, v2): # 自定义的标签可以定义多个参数
return v1 * v2
#3、自定义标签扩展之mark_safe
# 注释:我们可以用内置的标签safe来让标签内容有语法意义,如果我们想让自定义标签处理的结果也有语法意义,
# 则不能使用内置标签safe了,需要使用mark_safe,可以实现与内置标签safe同样的功能
from django.utils.safestring import mark_safe
@register.simple_tag
def my_input_tag(id, name):
res = "<input type='text' id='%s' name='%s' />" % (id, name)
return mark_safe(res)
4、在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py
<!-- HTML在使用 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--必须先加载存有自定义过滤器和标签的文件-->
{% load my_tags %}
<!--salary的值为10,经过滤器my_multi_filter的处理结果为120-->
{{ salary|my_multi_filter:12 }}
<!--结果为2-->
{% my_multi_tag 1 2 %}
<!--
结果为一个input标签,该表的属性id="inp1" name="username"
注意:input的属性值均为字符串类型,所以my_input_tag后的两个值均为字符串类型
-->
{% my_input_tag "inp1" "username" %}
</body>
</html>
- 在urls.py 和view.py 中 分布配置好才能生效
对比
#1、自定义过滤器只能传两个参数,而自定义标签却可以传多个参数
#2、过滤器可以用于if判断,而标签不能
{% if salary|my_multi_filter:12 > 200 %}
<p>优秀</p>
{% else %}
<p>垃圾</p>
{% endif %}
模板的导入和继承
- include
- extends
- block
母版:创建一个母版
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
{% block title %}自定义title名{% endblock %}
</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css"
integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
<style>
* {
margin: 0;
padding: 0;
}
.header {
height: 50px;
width: 100%;
background-color: #919191;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="header"></div>
<div class="container">
<div class="row">
<div class="col-md-3">
<div class="list-group">
{% block sidebar %}
<a href="#" class="list-group-item active">服装城</a>
<a href="#" class="list-group-item">美妆馆</a>
<a href="#" class="list-group-item">超市</a>
<a href="#" class="list-group-item">全球购</a>
<a href="#" class="list-group-item">闪购</a>
<a href="#" class="list-group-item">团购</a>
{% endblock %}
</div>
</div>
<div class="col-md-9">
{% block content %}
base.html页面内容
{% endblock %}
</div>
</div>
</div>
</body>
</html>
在base.html打上block 标签,实现母版的复用
block
{% extends "base.html" %}
<!--用新内容完全覆盖了父模板内容-->
{% block title %}
index页面
{% endblock %}
{% block sidebar %}
<!--该变量会将父模板中sidebar中原来的内容继承过来,然后我们可以在此基础上新增,否则就是纯粹地覆盖-->
{{ block.super }}
<!--在继承父模板内容的基础上新增的标签-->
<a href="#" class="list-group-item">拍卖</a>
<a href="#" class="list-group-item">金融</a>
{% endblock %}
{% block content %}
<!--用新内容完全覆盖了父模板内容-->
<p>index页面内容</p>
{% endblock %}
组件
可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。
{% include 'navbar.html' %}
总结
#1、标签extends必须放在首行,base.html中block越多可定制性越强
#2、include仅仅只是完全引用其他模板文件,而extends却可以搭配block在引用的基础上进行扩写
#3、变量{{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖
#4、为了提升可读性,我们可以给标签{% endblock %} 起一个名字 。例如:
{% block content %}
...
{% endblock content %}
#5、在一个模版中不能出现重名的block标签。
静态文件配置
在setting.py 中进行配置
STATIC_URL = '/static/' # 找到这一行,然后新增下述代码
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'statics'),# 获取静态文件在服务端的绝对路径
]
#STATIC_URL = '/static/'就是为静态文件的绝对路径起了一个别名,以后我们只需要用路径/static/即可
使用
一般不建议直接使用静态路径
static 的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--注意:必须先加载文件static.py-->
{% load static %}
<!--注意:此处的static是一个定义在static.py中的一个标签,名字与文件名一样而已,不要搞混-->
<link rel="stylesheet" href="{% static 'css/my.css' %}">
</head>
<body>
<h4>我是红色的,点我就绿</h4>
<img src="{% static 'img/rb.jpeg' %}" alt="">
{% load static %}
<script src="{% static 'js/jquery-3.3.1.min.js' %}"></script>
<script src="{% static 'js/my.js' %}"></script>
</body>
</html>
get_static_prefix 的使用
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<!--注意:同样需要先加载文件static.py-->
{% load static %}
<!--使用标签get_static_prefix拼接路径-->
<link rel="stylesheet" href="{% get_static_prefix %}css/my.css">
</head>
<body>
<h4>我是红色的,点我就绿</h4>
<img src="{% get_static_prefix %}img/rb.jpeg" alt="">
{% load static %}
<script src="{% get_static_prefix %}js/jquery-3.3.1.min.js"></script>
<script src="{% get_static_prefix %}js/my.js"></script>
</body>
</html>