Django模板层 (变量分配 过滤器 标签 继承和导入 自定义过滤器标签及inclusion_tag(了解))
Posted 每天的学习的知识都要记录!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Django模板层 (变量分配 过滤器 标签 继承和导入 自定义过滤器标签及inclusion_tag(了解))相关的知识,希望对你有一定的参考价值。
目录
一、模板变量分配
定义
在后端变量的值通过模板语法传到前端
-
符号
:主要与数据值相关
%%:主要与逻辑相关 -
模板语法注意点:
1.针对需要加括号调用的名字 django模板语法会自动加括号调用你只需要写名字就行
2.模板语法的注释##,前端浏览器是无法查看的,因为它要先在后端运行
3.django的模板语法是自己写的 跟jinja2不一样,只能用句点符的方式点出来 -
模板语法两种传值方法
return render(request, \'demo02.html\', \'n1\': name, \'a1\': age) # 传值方式1:精准传值 不浪费资源 针对多资源的传递书写麻烦
return render(request,\'demo02.html\', locals()) # 传值方式2:将函数名称空间中所有的名字全部传递 名字过多并且不使用的情况下比较浪费资源
- 模板语法传值特性
1.基本数据类型正常展示
2.文件对象也可以展示并调用方法
3.函数名会自动加括号执行并将返回值展示到页面上(不支持额外传参)
4.类名也会自动加括号调用,对象则不用加括号也可以调用(除非用魔法)
ps:总结针对可以加括号调用的名字模板语法都会自动加括号调用
- 代码展示
前端
<p> f </p>
<p> i </p>
<p> s </p>
<p> l </p>
<p> d </p>
<p> t </p>
<p> se </p>
<p> b </p>
<p> f_obj </p>
<p> f_obj.read </p>
<!--你能不能看到我-->
你看到了什么 快分享给我看看!!!
<p> func1 </p>
<p> MyClass </p>
<p> obj </p>
<p> obj.get_obj </p>
<p> obj.get_cls </p>
<p> obj.get_static </p>
后端
def func(request):
# python基本数据类型
f = 1.11
i = 666
s = \'hello jason! say hello big baby ha ha ha\'
l = [11, 22, 33, 44]
d = \'name\': \'jason\', \'age\': 18
t = (11, 22, 33, 44)
se = 11, 22, 33, 44
b = True
# 文件对象
f_obj = open(r\'D:\\pythonProject03\\djangoday04\\今日内容.md\', \'rb\')
# 函数
def func1():
print(\'上午犯困 下午也犯困 晚上还犯浑\')
return \'熬夜会上瘾\'
# 类
class MyClass(object):
def get_obj(self):
return \'绑定给对象的方法\'
@classmethod
def get_cls(cls):
return \'绑定给类的方法\'
@staticmethod
def get_static():
return \'静态方法\'
obj = MyClass()
页面效果
二、模板的过滤器
定义
模块语法自带的一些内置函数
语法
obj|filter__name:param 变量名字|过滤器名称:变量
-
default
如果一个变量是false或者为空,使用给定的默认值。否则,使用变量的值。例如:
value|default:"nothing"
- length
返回值的长度。它对字符串和列表都起作用。例如: 如果 value 是 [‘a’, ‘b’, ‘c’, ‘d’],那么输出是 4。
value|length
- filesizeformat
将值格式化为一个 “人类可读的” 文件尺寸 (例如 \'13 KB\', \'4.1 MB\', \'102 bytes\', 等等)。例如:如果 value 是 123456789,输出将会是 117.7 MB
value|filesizeformat
- date
如果 value=datetime.datetime.now()
value|date:"Y-m-d"
- slice
如果 value=”hello world”,将会是llo worl
value|slice:"2:-1"
- truncatechars
如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“…”)结尾。参数:要截断的字符数
value|truncatechars:9
- safe
Django的模板中会对HTML标签和JS等语法标签进行自动转义,原因显而易见,这样是为了安全。但是有的时候我们可能不希望这些HTML元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的,这些修饰可能是通过一个类似于FCKeditor编辑加注了HTML修饰符的文本,如果自动转义的话显示的就是保护HTML标签的源文件。为了在Django中关闭HTML的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉Django这段代码是安全的不必转义。比如:
value="<a href="">点击</a>"
value|safe
from django.utils.safestring import mark_safe
res = mark_safe(\'<h1>HELLO WORLD</h1>\')
- 代码展示
前端
<p> i|add:10 </p>
<p> s|add:\'baby\' </p>
<p> l|length </p>
<p> s|slice:\'1:4\' </p>
<p> value|slice:"2:-1"</p>
<p> s|truncatechars:5 </p>
<p> s|truncatewords:3 </p>
<p> ctime|date:\'Y年-m月-d日 H时:i分:s秒 \' </p>
<p> file_size|filesizeformat </p>
<p> h1|safe </p>
<p> s1|safe </p>
后端
def func(request):
from datetime import date,datetime
ctime = datetime.today()
import os
file_size = 424232423423432
h1 = \'<h1>哈哈哈哈</h1>\'
s1 = "<script>confirm(123)</script>"
return render(request, \'funcPage.html\', locals())
页面效果
三、模板之标签
- if标签
在html页面if ,然后tab键补全
语法
% if 条件1(可以自己写也可以用传递过来的数据) %
<p>今天又是周三了</p>
% elif 条件2(可以自己写也可以用传递过来的数据) %
<p>百日冲刺</p>
% else %
<p>没多少时间了!</p>
% endif %
- for标签
在html页面for ,然后tab键补全
语法
% for k in t1 %
% if forloop.first %
<p>这是我的第一次循环 k </p>
% elif forloop.last %
<p>这是我的最后一次循环 k </p>
% else %
<p>这是中间循环 k </p>
% endif %
% empty %
<p>你给我传的数据是空的无法循环取值(空字符串、空列表、空字典)</p>
% endfor %
- forloop关键字
# 遍历字典
# 字典的三剑客
keys values items
forloop.counter The current iteration of the loop (1-indexed) 当前循环的索引值(从1开始)
forloop.counter0 The current iteration of the loop (0-indexed) 当前循环的索引值(从0开始)
forloop.revcounter The number of iterations from the end of the loop (1-indexed) 当前循环的倒序索引值(从1开始)
forloop.revcounter0 The number of iterations from the end of the loop (0-indexed) 当前循环的倒序索引值(从0开始)
forloop.first True if this is the first time through the loop 当前循环是不是第一次循环(布尔值)
forloop.last True if this is the last time through the loop 当前循环是不是最后一次循环(布尔值)
forloop.parentloop 本层循环的外层循环
ps: django模板语法取值操作>>>:只支持句点符,句点符既可以点索引也可以点键
d1 = \'name\': \'jason\', \'age\': 18, \'hobby\': [\'read\', \'music\', \'a1\': \'haha\', \'a2\': \'heihei\']
d1.hobby.2.a1
- 起别名
复杂数据获取之后需要反复使用可以起别名
% with d1.hobby.2.a1 as h %
<a href=""> h </a>
% endwith %
四、自定义过滤器、标签及inclusion_tag(了解)
- 前期准备工作
如果想要自定义一些模板语法 需要先完成下列的三步走战略
1.在应用下创建一个名字必须叫templatetags的目录
2.在上述目录下创建任意名称的py文件
3.在上述py文件内先编写两行固定的代码
from django import template
register = template.Library()
- 自定义过滤器(最大只能接收两个参数)
@register.filter(name=\'myadd\')
def func1(a, b):
return a + b
目前编辑的页面代码
% load mytags % # 加载自己创建的py文件
<p> i|myadd:1 </p>
- 自定义标签(参数没有限制)
@register.simple_tag(name=\'mytag\')
def func2(a, b, c, d, e):
return f\'a-b-c-d-e\'
目前编辑的页面代码
% load mytags % # 加载自己创建的py文件
% mytag \'jason\' \'kevin\' \'oscar\' \'tony\' \'lili\' %
- 自定义inclusion_tag(局部的html代码)
调用函数,在一个自己新建的空html文件中执行,执行完后再塞进需要用的html页面
@register.inclusion_tag(\'menu.html\',name=\'mymenu\')
def func3(n):
html = []
for i in range(n):
html.append(\'<li>第%s页</li>\'%i)
return locals()
新建的借助menu.html页面代码
<ul>
% for liStr in html %
liStr|safe
% endfor %
</ul>
目前编辑的页面代码
% load mytags % # 加载自己创建的py文件
% mymenu 20 %
五、模板的继承和导入
模板的继承(重要)
定义
多个页面有很多相似的地方 我们可以采取下列方式
- 方式1:传统的复制粘贴
- 方式2:模板的继承
1.在模板中使用block划定子板以后可以修改的区域
% block 区域名称 %
继承的旧代码区域
% endblock %
2.子板继承模板
% extends \'home.html\' % # 首先要先导入母版
% block 区域名称 %
继承的新代码区域
% endblock %
补充:子板也可以继续使用模板的内容
block.super
ps:模板中至少应该有三个区域,分别是页面内容区、css样式区、js代码区
模板的导入(了解)
定义
将某个html的部分提前在一个空的html页面写好 之后很多html页面都想使用就可以导入,在需要导入的地方
% include \'myform.html\' %
直接上代码,以后可以粘贴复制
- 母板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
# <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.1/jquery.js"></script>#
# <link rel="stylesheet" href="bootstrap-3.4.1-dist/css/bootstrap.css">#
# <script src="bootstrap-3.4.1-dist/js/bootstrap.js"></script>#
% load static %
<script src="% static \'jquery.min.js\' %"></script>
<link rel="stylesheet" href="% static \'bootstrap-3.4.1-dist/css/bootstrap.min.css\' %">
<script src="% static \'bootstrap-3.4.1-dist/js/bootstrap.min.js\' %"></script>
<style>
.c1
float: left;
</style>
</head>
<body>
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">羊村登录管理系统</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">模块</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="#">链接<span class="sr-only">(current)</span></a></li>
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">下载 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">版本</a></li>
<li><a href="#">其他活动</a></li>
<li><a href="#">其他一些好玩的</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">点击有惊喜</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">不信点这里</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
<li><a href="#">Link</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true"
aria-expanded="false">Dropdown <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
<div class="container-fluid">
<div class="row">
<div class="col-lg-4">
<!-- Single button -->
<div class="btn-group">
<button type="button" class="btn btn-default dropdown-toggle" data-toggle="dropdown"
aria-haspopup="true" aria-expanded="false">
Action <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
</ul>
</div>
<div class="list-group">
<a href="#" class="list-group-item disabled">
网页基本功能
</a>
<a href="/child1/" class="list-group-item">登录</a>
<a href="/child2/" class="list-group-item">注册</a>
<a href="#" class="list-group-item">编辑</a>
<a href="#" class="list-group-item">删除</a>
</div>
<ul class="list-group">
<li class="list-group-item list-group-item-success">Dapibus ac facilisis in</li>
<li class="list-group-item list-group-item-info">Cras sit amet nibh libero</li>
<li class="list-group-item list-group-item-warning">Porta ac consectetur ac</li>
<li class="list-group-item list-group-item-danger">Vestibulum at eros</li>
</ul>
<div class="list-group">
<a href="#" class="list-group-item list-group-item-success">青青草原第一飞毛腿-喜哥</a>
<a href="#" class="list-group-item list-group-item-info">青青草原第一睡神-懒哥</a>
<a href="#" class="list-group-item list-group-item-warning">青青草原第一美女-美姐</a>
<a href="#" class="list-group-item list-group-item-danger">青青草原第一帅哥-狼哥</a>
</div>
<nav aria-label="...">
<ul class="pagination">
<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>
</li>
<li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
<li class="active"><a href="#">2 <span class="sr-only">(current)</span></a></li>
<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>
</li>
<li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>
</li>
<li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
<li class="disabled"><a href="#" aria-label="Previous"><span aria-hidden="true">«</span></a>
</li>
<li class="active"><a href="#">1 <span class="sr-only">(current)</span></a></li>
</ul>
</nav>
</div>
<div class="col-lg-8">
% block content %
<div class="panel panel-warning">
<div class="jumbotron">
<h1>这里青青草原的网页</h1>
<p>里面记录着羊村和狼堡的信息</p>
<p><a class="btn btn-primary btn-lg" href="#" role="button">了解羊村</a></p>
</div>
</div>
<div class="panel panel-success">
<div class="row">
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="https://img1.baidu.com/it/u=1682278568,1662583579&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
>
</a>
</div>
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="https://img1.baidu.com/it/u=1236718530,2234744473&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=505"
>
</a>
</div>
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="https://img2.baidu.com/it/u=660177652,3207960518&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=500"
>
</a>
</div>
<div class="col-xs-6 col-md-3">
<a href="#" class="thumbnail">
<img src="https://img1.baidu.com/it/u=4028757630,2942084939&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=499"
>
</a>
</div>
</div>
<div class="panel panel-info">
<div class="row">
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://img1.baidu.com/it/u=259115010,423465834&fm=253&fmt=auto&app=138&f=PNG?w=500&h=565"
>
<div class="caption">
<h3>武大狼的第250代子孙,第77代狼王,自称“本大王”,喜羊羊等人也称他为“灰太狼大王”。疼爱孩子的好丈夫、好爸爸。</h3>
<p>...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#"
class="btn btn-default"
role="button">Button</a>
</p>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://img1.baidu.com/it/u=2822434814,2828561864&fm=253&fmt=auto&app=138&f=JPEG?w=500&h=427"
>
<div class="caption">
<h3>
黑大帅,动画片《喜羊羊与灰太狼》系列中的反派角色,后来成为正面角色,初登场于动画《喜羊羊与灰太狼之古古怪界大作战》第4集(即《喜羊羊与灰太狼》第一部第284集)作为反派角色,来自地底下的古古怪界。</h3>
<p>...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#"
class="btn btn-default"
role="button">Button</a>
</p>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4">
<div class="thumbnail">
<img src="https://img2.baidu.com/it/u=2970440372,1083416465&fm=253&fmt=auto&app=138&f=JPEG?w=572&h=500"
>
<div class="caption">
<h3>
武泰哥,又称老虎大叔。为国产动画片《喜羊羊与灰太狼》系列中出现的人物,原型是一只金黄色的华南虎,四臂有健壮的肌肉,胸部点缀着两大块胸肌。常常举行肌肉展示,包包大人为他伤透了脑筋。 </h3>
<p>...</p>
<p><a href="#" class="btn btn-primary" role="button">Button</a> <a href="#"
class="btn btn-default"
role="button">Button</a>
</p>
</div>
</div>
</div>
</div>
</div>
<div class="panel panel-warning">...</div>
<div class="panel panel-danger">...</div>
</div>
</div>
% endblock %
</div>
</div>
</body>
</html>
- 子板1
% extends \'Monpage.html\' %
% block css %
<style>
#d2
color: yellow;
</style>
% endblock %
% block content %
<h1 class="text-center" id="d2">登录页面</h1>
% include \'daoru.html\' %
<form action="">
<p>username:
<input type="text" class="form-control">
</p>
<p>password:
<input type="text" class="form-control">
</p>
<input type="submit" class="btn btn-warning btn-block">
</form>
% endblock %
% block js %
<script>alert(\'注册页面\')</script>
% endblock %
- 子板2
% extends \'Monpage.html\' %
% block css %
<style>
#d2
color: yellow;
</style>
% endblock %
% block content %
<h1 class="text-center" id="d2">注册页面</h1>
% include \'daoru.html\' %
<form action="">
<p>username:
<input type="text" class="form-control">
</p>
<p>password:
<input type="text" class="form-control">
</p>
<input type="submit" class="btn btn-warning btn-block">
</form>
% endblock %
% block js %
<script>alert(\'注册页面\')</script>
% endblock %
- 母板页面效果
- 子板页面效果
Django之模板层
Django之模板层
一 、模板简介
在刚刚介绍完的视图层中我们提到,浏览器发送的请求信息会转发给视图函数进行处理,而视图函数在经过一系列处理后必须要有返回信息给浏览器。如果我们要返回html标签、css等数据给浏览器进行渲染,我们可以在视图函数中这么做
def current_datetime(request):
now = datetime.datetime.now()
html = "<html><body>It is now %s.</body></html>" % now
return HttpResponse(html)
上例所示,我们直接将HTML代码放到视图函数里,然后进行返回,这可以使我们很直观地看清楚浏览器从发送请求到看到前端界面内容的这个过程中视图函数的基本工作原理,但是这种将前端代码与后端代码耦合到了一起开发方式,会存在以下问题
1、程序的可维护性与可扩展性问题
前端界面一旦需要重新设计、修改,则必须对后端的Python代码进行相应的修改。 然而前端界面的修改往往比后端 Python 代码的修改要频繁得多,因此如果可以在不进行 Python 代码修改的情况下变更前端界面的设计,那将会方便得多。
2、开发效率问题
Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将它们分配给不同的人员(甚至不同部门)来完成。 专门的程序员去编写 Python代码、专门的设计人员去制作模板,这两项工作同时进行,效率才是最高的。
基于上述原因,将前端页面和Python的代码分离是一种不错的开发模式。 为此 Django专门提供了模板系统 (Template System,即模板层)来实现这种模式,这就是本章要具体讨论的问题。
django的模板=HTML代码+模板语法
存放于templates目录下的html文件称之为模板文件,如果我们想要返回的html页面中的数据是动态的,那么必须在html页面中嵌入变量,这便用到了django的模板语法,具体来说,django的模板语法有以下重点
一、变量:{{ 变量名 }}
1.1 深度查询:句点符的应用
1.2 过滤器
二、标签:{% 标签名 %}
三、自定义标签和过滤器
四、模板的导入和继承
下面就让我们来一一介绍它们
二 、模板语法之变量
2.1 变量的基本使用
如果html代码中的数据不是固定死的,而是动态变化的,则必须在html中嵌入变量,为此,模板语法提供了变量的概念,允许我们在html代码中嵌入变量,我们只需要在视图函数中用render方法为html文件中指定的变量赋值即可,具体用法如下
test.html
<!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>
我们需要在视图函数中为模板test.html的变量名msg、li、dic、obj、obj_li赋值,views.py内容如下
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
2.2 深度查询之句点符的使用
当视图函数传给模板的值中包含多个元素时,若想取出其中的单个元素,就必须使用句点符了。
句点符既可以引用容器类型的元素,也可以引用对象的方法,如下
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<!--调用字符串对象的upper方法,注意不要加括号-->
<p>{{ msg.upper }}</p>
<!--取字典中k1对应的值-->
<p>{{ dic.k1 }}</p>
<!--取对象的name属性-->
<p>{{ obj.name }}</p>
<!--取列表的第2个元素,然后变成大写-->
<p>{{ li.1.upper }}</p>
<!--取列表的第3个元素,并取该元素的age属性-->
<p>{{ li.2.age }}</p>
</body>
</html>
2.3 过滤器
过滤器类似于python的内置函数,用来把视图传入的变量值加以修饰后再显示,具体语法如下
{{ 变量名|过滤器名:传给过滤器的参数 }}
常用内置过滤器
#1、default
#作用:如果一个变量值是False或者为空,使用default后指定的默认值,否则,使用变量本身的值,如果value=’‘则输出“nothing”
{{ value|default:"nothing" }}
#2、length
#作用:返回值的长度。它对字符串、列表、字典等容器类型都起作用,如果value是 ['a', 'b', 'c', 'd'],那么输出是4
{{ value|length }}
#3、filesizeformat
#作用:将值的格式化为一个"人类可读的"文件尺寸(如13KB、4.1 MB、102bytes等等),如果 value 是 12312312321,输出将会是 11.5 GB
{{ value|filesizeformat }}
#4、date
#作用:将日期按照指定的格式输出,如果value=datetime.datetime.now(),按照格式Y-m-d则输出2019-02-02
{{ value|date:"Y-m-d" }}
#5、slice
#作用:对输出的字符串进行切片操作,顾头不顾尾,如果value=“egon“,则输出"eg"
{{ value|slice:"0:2" }}
#6、truncatechars
#作用:如果字符串字符多于指定的字符数量,那么会被截断。截断的字符串将以可翻译的省略号序列(“...”)结尾,如果value=”hello world egon 嘎嘎“,则输出"hello...",注意8个字符也包含末尾的3个点
{{ value|truncatechars:8 }}
#7、truncatewords
#作用:同truncatechars,但truncatewords是按照单词截断,注意末尾的3个点不算作单词,如果value=”hello world egon 嘎嘎“,则输出"hello world ..."
{{ value|truncatewords:2 }}
#8、safe
#作用:出于安全考虑,Django的模板会对HTML标签、JS等语法标签进行自动转义,例如value="<script>alert(123)</script>",模板变量{{ value }}会被渲染成<script>alert(123)</script>交给浏览器后会被解析成普通字符”<script>alert(123)</script>“,失去了js代码的语法意义,但如果我们就想让模板变量{{ value }}被渲染的结果又语法意义,那么就用到了过滤器safe,比如value='<a href="https://www.baidu.com">点我啊</a>',在被safe过滤器处理后就成为了真正的超链接,不加safe过滤器则会当做普通字符显示’<a href="https://www.baidu.com">点我啊</a>‘
{{ value|safe }}
其他过滤器(了解)
过滤器 | 描述 | 示例 |
---|---|---|
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:’’ }} 返回 abc45 |
length | 返回列表中元素的个数或字符串长度 | |
length_is | 检查列表,字符串长度是否符合指定的值 | {{ ‘hello’| length_is:’3’ }} |
linebreaks | 用或 标签包裹变量 | {{ “Hi David”|linebreaks }} 返回HiDavid |
linebreaksbr | 用 标签代替换行符 | |
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标签 | {{ ‘<p>This is a pen</p>‘ | truncatewords:2 }}返回``<p>This is ...</p> |
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 |
三、 模板语法之标签
标签是为了在模板中完成一些特殊功能,语法为{% 标签名 %},一些标签还需要搭配结束标签 {% endtag %}
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 %}
案例
url.py
from django.urls import re_path
from app01 import views
urlpatterns = [
re_path(r'^test/',views.test)
]
view.py
def test(request):
names=['egon','kevin']
dic={'name':'egon','age':18,'sex':'male'}
list1=[]
return render(request,'test.html',locals())
test.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<hr>
{% for name in names %}
<p>{{ forloop.counter0 }} {{ name }}</p>
{% endfor %}
<!--
输出结果为:
0 egon
1 kevin
-->
<hr>
{% for name in names reversed %}
<p>{{ forloop.revcounter0 }} {{ name }}</p>
{% endfor %}
<!--
输出结果为:
1 kevin
0 egon
-->
<hr>
{% for k,v in dic.items %}
<p>{{ forloop.counter }} {{ k }} {{ v }}</p>
{% endfor %}
<!--
输出结果为:
1 name egon
2 age 18
3 sex male
-->
<hr>
{% for item in list1 %}
<p>{{ item }}</p>
{% empty %}
<p>sorry,no value here</p>
{% endfor %}
<!--
输出结果为:
sorry,no value here
-->
</body>
</html>
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判断。
案例
urls.py
from django.urls import path,register_converter,re_path
from app01 import views
urlpatterns = [
# 输入http://127.0.0.1:8008/或者http://127.0.0.1:8008/index/都会转发给视图函数index
re_path(r'^$',views.index),
re_path(r'^index/$',views.index),
re_path(r'^login/',views.login),
]
views.py
from django.shortcuts import render
def index(request):
return render(request,'index.html')
def login(request):
if request.method == 'GET':
return render(request,'login.html')
name=request.POST.get('name')
pwd=request.POST.get('pwd')
if name == 'egon' and pwd == '123':
current_user=name
return render(request,'index.html',locals())
else:
msg='账号或密码错误'
return render(request,'login.html',locals())
在templates目录下新建模板文件index.html与login.html
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>首页</title>
</head>
<body>
<h3>首页</h3>
<!--
如果用户已经登录,则current_user变量有值,if判断结果为真,会打印变量current_user的值,为当前登录的用户名
如果用户没有登录,则current_user变量无值,if判断结果为假,会打印a标签要求用户先登录
-->
{% if current_user %}
<p>当前登录用户为:{{ current_user }}</p>
{% else %}
<p><a href="/login/">请先登录</a></p>
{% endif %}
</body>
</html>
login.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登录页面</title>
</head>
<body>
<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>
<!--输错账号密码时的提示信息-->
<p style="color: red">{{ msg }}</p>
</body>
</html>
测试
python manage.py runserver 8008 #在浏览器输入http://127.0.0.1:8008/,然后点击登录,输入账号密码进行验证......
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请求,否则拒绝,以此来确定客户端的身份
四 、自定义过滤器和标签
当内置的过滤器或标签无法满足我们需求时,我们可以自定义,具体操作步骤如下
1、在settings中的INSTALLED_APPS添加当前app的名字,不然django无法找到自定义的过滤器或标签
settings.py
# 在settings.py中找到该列表,然后加以配置
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app01.apps.App01Config',
'app01', # 添加当前app的名字
]
2、在文件夹app01中创建子文件夹templatetags(文件夹名只能是templatetags)
3、在templatetags新建任意.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、自定义过滤器或标签必须重新启动django方可生效
5、自定义过滤器或标签的使用
<!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>
对比自定义标签与自定义过滤器
#1、自定义过滤器只能传两个参数,而自定义标签却可以传多个参数
#2、过滤器可以用于if判断,而标签不能
{% if salary|my_multi_filter:12 > 200 %}
<p>优秀</p>
{% else %}
<p>垃圾</p>
{% endif %}
五 、模板的导入和继承
在实际开发中,模板文件彼此之间可能会有大量冗余代码,为此django提供了专门的语法来解决这个问题,主要围绕三种标签的使用:include标签、extends标签、block标签,详解如下
5.1、模板的导入之include标签
#作用:在一个模板文件中,引入/重用另外一个模板文件的内容,
{% include '模版名称' %}
案例:
可以把广告栏写到专门的文件里advertise.html
<div class="adv">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading">
<h3 class="panel-title">Panel title</h3>
</div>
<div class="panel-body">
Panel content
</div>
</div>
</div>
然后在base.html文件中用include标签引入advertise.html文件的内容
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</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: black;
}
</style>
</head>
<body>
<div class="header"></div>
<div class="container">
<div class="row">
<div class="col-md-3">
<!--在base.html引入advertise.html文件的内容-->
{% include "advertise.html" %}
</div>
<div class="col-md-9"></div>
</div>
</div>
</body>
</html>
5.2、模板的继承派生之extends标签、block标签
#作用:在一个模板文件中,引入/重用另外一个模板文件的内容
{% extends "模版名称" %}
# 也就是说include有的功能extends全都有,但是extends可以搭配一个block标签,用于在继承的基础上定制新的内容
案例
Django模版引擎中最复杂且最强大的部分就是模版继承了。我们以先创建一个基本的“骨架”模版,它包含我们站点中的全部元素,并且可以定义多处blocks ,例如我们创建base.html内容如下
<!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 定义了一个可以用于两列排版页面的简单HTML骨架。我们新建子模板index.html的主要工作就是继承base.html然后填充/覆盖其内部的blocks。
{% 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 %}
我们通过django访问index.html看到内容如下(block标签的内容都完成了替换或更新)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>
index页面
</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">
<!--该变量会将父模板中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>
<!--在继承父模板内容的基础上新增的标签-->
<a href="#" class="list-group-item">拍卖</a>
<a href="#" class="list-group-item">金融</a>
</div>
</div>
<div class="col-md-9">
<!--用新内容完全覆盖了父模板内容-->
<p>index页面内容</p>
</div>
</div>
</div>
</body>
</html>
总结与注意
#1、标签extends必须放在首行,base.html中block越多可定制性越强
#2、include仅仅只是完全引用其他模板文件,而extends却可以搭配block在引用的基础上进行扩写
#3、变量{{ block.super }} 可以重用父类的内容,然后在父类基础上增加新内容,而不是完全覆盖
#4、为了提升可读性,我们可以给标签{% endblock %} 起一个名字 。例如:
{% block content %}
...
{% endblock content %}
#5、在一个模版中不能出现重名的block标签。
六、静态文件配置
我们在编写模板文件时,需要大量引用css、js、图片等静态文件,如果我们将这些文件在服务端存放的路径都固定写死那么将非常不利于后期的扩展,我们可以这么做
1、settings.py
STATIC_URL = '/static/' # 找到这一行,然后新增下述代码
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'statics'),# 获取静态文件在服务端的绝对路径
]
#STATIC_URL = '/static/'就是为静态文件的绝对路径起了一个别名,以后我们只需要用路径/static/即可
2、在项目根目录下新增文件夹statics,为了更便于管理,可以在statics下新建子文件夹css、js、img等
3、新建模板文件index.html,在该文件中对静态文件的引用如下
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/css/my.css">
</head>
<body>
<h4>我是红色的,点我就绿</h4>
<img src="/static/img/rb.jpeg" alt="">
<script src="/static/js/jquery-3.3.1.min.js"></script>
<script src="/static/js/my.js"></script>
</body>
</html>
综上,在配置完settings.py后,所有的静态文件路径都可以采用别名/static/作为起始,这在一定程度上会有利于程序的扩展性,但如果我们在项目后期维护时,连/static/这个值也需要修改,那意味着所有模板文件中也都需要跟着改了,扩展性依然很差,为此,django在一个名为static.py的文件中定义了标签static、get_static_prefix,二者都可以解决该问题
test.html
<!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>
标签static会接收传入的参数,然后这根据settings.py中变量STATIC_URL的值拼接出一个完整的路径,如果STATIC_URL = ‘/static/‘,那么href="{% static ‘css/my.css‘ %}"会被渲染成href="/static/css/my.css",如果STATIC_URL = ‘/static123/‘,那么href="{% static ‘css/my.css‘ %}"会被渲染成href="/static123/css/my.css"。
标签get_static_prefix也可以完成同样的效果,只不过用法不同。我们不能为标签get_static_prefix传参,因为标签get_static_prefix代表的只是settings.py中STATIC_URL的值,所以我们需要做的是在get_static_prefix的基础上自行拼接路径,如下
test.html
<!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>
如果STATIC_URL = ‘/static/‘,那么href="{% get_static_prefix %}css/my.css"会被渲染成href="/static/css/my.css",其它同理
以上是关于Django模板层 (变量分配 过滤器 标签 继承和导入 自定义过滤器标签及inclusion_tag(了解))的主要内容,如果未能解决你的问题,请参考以下文章