django 模版 语法与使用
程序员文章站
2022-04-08 13:01:43
django 模版语法与使用 [TOC] django模板语言介绍 (摘自官方文档) 链接 什么是模板? 模板语句的 注释 变量 {{ 变量 }} 变量:语法为 {{ }}:括号里加要渲染变量的变量值,变量名由字母数字和下划线组成。 代码 浏览器结果: 小结: {{ }}里填要渲染的变量,规范写法, ......
django 模版语法与使用
django模板语言介绍 (摘自官方文档) 链接
""" django模板语言 django的模板语言旨在在功能和易用性之间取得平衡。它让那些习惯使用html的人感到舒服。 如果您对其他基于文本的模板语言(如smarty 或jinja2)有过接触,那么您应该对django的模板感到宾至如归。 哲学 如果您有编程背景,或者习惯于将编程代码直接混合到html中的语言,那么您需要记住, django模板系统不仅仅是嵌入到html中的python。这是一种设计,模板系统用于表达,而不是程序逻辑。 django模板系统提供的标签功能类似于一些编程结构 如 if,布尔,for标签,循环标签等 - 但这些标签不是简单地作为相应的python代码执行, 模板系统不会执行任意python表达式。默认情况下,仅支持下面列出的标记,过滤器和语法(您可以根据需要将自己的扩展添加到模板语言中)。 哲学 为什么使用基于文本的模板而不是基于xml的模板(如zope的tal)?我们希望django的模板语言不仅可用于xml / html模板。 在world online,我们将其用于电子邮件,javascript和csv。您可以将模板语言用于任何基于文本的格式。 哦,还有一件事:让人类编辑xml是虐待狂! """
什么是模板?
模板只是一个文本文件。它可以生成任何基于文本的格式(html,xml,csv等)。 模板包含变量,这些变量在评估模板时将替换为值,而变量则包含控制模板逻辑的标记。 只要是在html里面有模板语法就不是html文件了,这样的文件就叫做模板。
模板语句的 注释
模板语句的注释 {#{{ '10'|add_str:'5 '}}#} {#注释内容#}
变量 {{ 变量 }}
变量:语法为 {{ }}:括号里加要渲染变量的变量值,变量名由字母数字和下划线组成。
代码
#views 文件函数 def template_test(request): name = '钢蛋' age = 18 hobby = ['唱', '跳', 'rap', '篮球'] lis = [] st = '' dic = { 'name': '铁蛋', 'age': 16, 'hobby': hobby, 'keys': 'xxxxx' } dic_2 = {} return render(request,'template_test.html', {'name':name_p,'age':age,'hobby':hobby,'lis':lis,'st':st,'dic':dic,'dic_2':dic_2}) # 模板文件html页面 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>郭楷丰</title> </head> <body> {{ 啦啦啦啦啦 }} <p> {{ name }} </p> <p> {{ age }} </p> <p> {{ hobby }} </p> <p> {{ lis }} </p> <p> {{ st }} </p> <p> {{ dic }} </p> <p> {{ dic_2 }} </p> </body> </html>
- 浏览器结果:
- 小结: {{ }}里填要渲染的变量,规范写法,两边用括号隔开 如 {{ 变量 }}, 后端没有传参的页面不显示
点(.)在模板语言中有特殊的含义,用来获取对象的相应属性值。
- 例子 代码 .索引 .key .属性 .方法
#views 文件函数 def template_test(request): lis = [1, 2, 3,4,5] dic = {"name": "黑蛋"} class person(object): def __init__(self, name, age): self.name = name self.age = age def dream(self): return " 我 is {} age {}岁...".format(self.name,self.age) gangdan = person(name="钢蛋", age=18) goudan = person(name="狗蛋", age=17) tiedan = person(name="铁蛋", age=16) person_list = [gangdan, goudan, tiedan] return render(request, "template_test.html", {"lis": lis, "dic": dic, "person_list": person_list}) # 模板文件html页面 <!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <title>郭楷丰</title> </head> <boby> <p>{{ lis.0 }}</p> <!--取l中的第一个参数--> <p>{{ dic.name }}</p><!--取字典中key的值--> <p>{{ person_list.0.name }}</p><!--取对象的name属性--> <p>{{ person_list.0.dream }}</p><!--.操作只能调用不带参数的方法--> </boby> </html>
- 小结:
#注:当模板系统遇到一个(.)时,会按照如下的顺序去查询: 1. 在字典中查询 2. 属性或者方法 3. 数字索引 # 索引不能为负数
tags 标签 {% %} 表示逻辑相关的操作
- 代码例子
{% for foo in lis %} <!--for循环--> {% if %} <!--if判断--> {% elif %} <!--elif判断--> {% endif %} <!--if闭合符--> {% else %} <!--else判断不成立执行--> {% endfor %} <!--for循环闭合符--> <!--应用 模板html代码--> <form action="" method="post"> <label for="inputemail3" class="col-sm-2 control-label">书名: </label> <div class="col-sm-8"> <input type="text" name="book_name" class="form-control" value="{{ edit_obj.title }}"> <select name="pub_id" id="" class="btn btn-default btn-sm"> {% for foo in publishers %} {% if foo == edit_obj.pub %} <option selected value="{{ foo.pk }}"> {{ foo.name }}</option> {% else %} <option value="{{ foo.pk }}"> {{ foo.name }}</option> {% endif %} {% endfor %} </select> </div> <div class="text-center text-danger">{{ error }}</div> <div class="col-sm-offset-2 col-sm-10"> <button type="submit" class="btn btn-default">提交</button> </div> </form> <!--应用 python逻辑代码 #views 文件函数--> def edit_book(request): error = '' pk = request.get.get('pk') edit_obj = models.book.objects.filter(id=pk) if not edit_obj: return httpresponse('要编辑的数据不存在') if request.method == 'post': book_name = request.post.get('book_name') if not book_name.strip(): error = "书名不能为空" pub_id = request.post.get('pub_id') if edit_obj[0].title == book_name and edit_obj[0].pub_id == int(pub_id): error = "未作修改" if not error: obj = edit_obj[0] obj.title = book_name obj.pub_id = int(pub_id) obj.save() return redirect('/book_list/') publishers = models.publisher.objects.all() return render(request,'edit_book.html',{'edit_obj':edit_obj[0],'publishers':publishers,'error':error})
- 执行效果
if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断。
-
js,python,模板语言的判断逻辑
#python 10>5>1 =》 10>5 and 5>1 true #js 10>5>1 =》 10>5 =》 true =》 1>1 false #模板中 不支持连续连续判断,也不支持算数运算(过滤器)
注意事项
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的值。
for循环可用的一些参数:
variable | description |
---|---|
forloop.counter |
当前循环的索引值(从1开始) |
forloop.counter0 |
当前循环的索引值(从0开始) |
forloop.revcounter |
当前循环的倒序索引值(到1结束) |
forloop.revcounter0 |
当前循环的倒序索引值(到0结束) |
forloop.first |
当前循环是不是第一次循环(布尔值) |
forloop.last |
当前循环是不是最后一次循环(布尔值) |
forloop.parentloop |
本层循环的外层循环 |
filters 过滤器
用来修改变量的显示结果, 语法: {{ value|filter_name:参数 }} ':' 左右没有空格没有空格没有空格
设置除法除尽 divisibleby:参数
with 的使用
- 定义一个中间变量(起个别名,只在with内部生效)
#写法一 {% with total=business.employees.count %} {{ total }} employee{{ total|pluralize }} {% endwith %} #写法二 {% with business.employees.count as total %} {{ total }} employee{{ total|pluralize }} {% endwith %}
default 系统默认值
{{ value|default:"nothing"}} 如果value值没传的话就显示nothing 注:templates的options可以增加一个选项:string_if_invalid:'找不到',可以替代default的的作用。 (在配置文件settings.py设置)
- 配置设置变量不传参显示值
- 页面效果
filesizeformat 文件大小人性化显示
- 将值格式化为一个 “人类可读的” 文件尺寸 (例如 '13 kb', '4.1 mb', '102 bytes', 等等)例如:
{{ value|filesizeformat }} 如果 value 是 123456789,输出将会是 117.7 mb
add "加"
- 给变量加参数,字符串默认尝试转int类型,转不了就拼接
{{ value|add:"2" }} value是数字4,则输出结果为6 {{ value|add:"hello" }} value是数字666,则输出结果为666hello {{ first|add:second }} 如果first是 [1,.2,3] ,second是 [4,5,6] ,那输出结果是 [1,2,3,4,5,6]
lower 小写
{{ value|lower }}
upper 大写
{{ 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}} truncatewords 按照单词进行截断, 只针对英文
date 日期格式化
#后端 import datetime def mul(request): value = datetime.datetime.now() return render(request, 'mul.html',{'value':value}) #模板语句 {{ value|date:"y-m-d h:i:s"}} #显示格式 年-月-日 时:分:秒 #后端 import datetime def mul(request): now = datetime.datetime.now() return render(request, 'mul.html',{'now':now}) #模板直接使用变量 {{ now }} #显示格式 june 19,2019,22:00 p.m.
- 页面效果
- 可格式化输出的字符: 点击查看
- 改配置文件设置显示样式 (一劳永逸的解决办法)
#settings.py文件设置 use_l10n = false #更换为false datetime_format = 'y-m-d h:i:s' #添加 #也可以日期与时间分开设置 根据自己的需求设置 date_format = 'y-m-d' time_format = 'h:i:s'
safe 防止xss攻击 作用 取消转义
- 简单了解xss攻击
xss攻击全称跨站脚本攻击,是为不和层叠样式表(cascading style sheets, css)的缩写混淆, 故将跨站脚本攻击缩写为xss,xss是一种在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。 xss是一种经常出现在web应用中的计算机安全漏洞,它允许恶意web用户将代码植入到提供给其它用户使用的页面中。 比如这些代码包括html代码和客户端脚本。攻击者利用xss漏洞旁路掉访问控制——例如同源策略(same origin policy)。 这种类型的漏洞由于被骇客用来编写危害性更大的网络钓鱼(phishing)攻击而变得广为人知。对于跨站脚本攻击, 骇客界共识是:跨站脚本攻击是新型的“缓冲区溢出攻击“,而javascript是新型的“shellcode”。
- xss攻击流程
safe 主要作用
#django的模板中会对html标签和js等语法标签进行自动转义,原因显而易见,这样是为了安全。 但是有的时候我们可能不希望这些html元素被转义,比如我们做一个内容管理系统,后台添加的文章中是经过修饰的, 这些修饰可能是通过一个类似于fckeditor编辑加注了html修饰符的文本,如果自动转义的话显示的就是保护html标签的源文件。 为了在django中关闭html的自动转义有两种方式,如果是一个单独的变量我们可以通过过滤器“|safe”的方式告诉django这段代码是安全的不必转义。
- 正常情况下
#页面代码: {% load my_tags %} {{ 'https://www.baidu.com/'|show:'百度' }} #自定过滤器代码 @register.filter def show(url,name): return "<a href = '{}'>{}</a>".format(url,name)
- 页面显示效果
- 过滤器函数 加is_safe = true 解除转义
#自定过滤器代码 @register.filter(is_safe = true) def show(url,name): return "<a href = '{}'>{}</a>".format(url,name)
页面效果
模板语句中加 safe 解除转义
#模板语句 {% load my_tags %} {{ 'https://www.baidu.com/'|show:'百度'|safe }}
页面效果
也可以导入模块实现这种效果
自定义 filter
- 当普通的内置过滤器,实现不了我们的开发需求,那我们可以自定义过滤器来实现功能
自定义过滤器是只能带有一个或两个参数的python函数: 变量(输入)的值 - -不一定是一个字符串 参数的值 - 这可以有一个默认值,或完全省略 例如,在过滤器{{var | foo:“bar”}}中,过滤器foo将传递变量var和参数“bar”。 自定义filter代码文件摆放位置: app01/ __init__.py models.py templatetags/ # 在app01下面新建一个package package __init__.py app01_filters.py # 建一个存放自定义filter的py文件 views.py
自定义过滤器流程
- 1 在app下创建一个名为templatetags的python包
#注意 在settings中的installed_apps配置当前app,不然django无法找到自定义的simple_tag (模块名只能是templatetags)
2 在python中创建py文件,文件名可以自定义 如:(my_tags.py)
3 在py文件中写:
from django import template register = template.library() #固定写法,不可改变
- 4 写函数+装饰器
@register.filter #过滤器 def add_str(value, arg): # 最多有两个 return '{}-{}'.format(value, arg)
- 5 写页面代码 在使用自定义simple_tag和filter的html文件中导入之前创建的 my_tags.py
{% load my_tags %} #先导入我们自定义那个文件 my_tags {{ name|add_str:age }} #参数只能是两个,一个参数是变量name ,一个是参数是后面的那个参数age
- 执行结果
自定义乘法过滤器 multioly
#过滤器函数 @register.filter def multiply1(value,arg): return value * arg #模板语句 {% load my_tags %} <p>{{ 6|multiply1:'6' }}</p> <p>{{ 6|multiply1:6 }}</p> <p>{{ '10'|multiply1:5 }}</p>
- 执行结果
自定义除法过滤器 division
#过滤器函数 @register.filter def division(value,arg): return value / arg #模板语句 {% load my_tags %} <p>{{ 6|division:6 }}</p> <p>{{ 6|division:1 }}</p>
- 执行结果
自定义除法过滤器 add
#过滤器函数 @register.filter def add(value,arg): return value + arg #可以这样写,但是转换不了会报错 int(value) + int(arg) #模板语句 {% load my_tags %} <p>{{ 6|add:6 }}</p> <p>{{ 6|add:0 }}</p> <p>{{ '钢蛋g'|add:18 }}</p>
- 执行结果
自定义减法过滤器 subtraction
#过滤器函数 @register.filter def add(value,arg): return value - arg #模板语句 {% load my_tags %} <p>{{ 6|add:6 }}</p> <p>{{ 6|add:0 }}</p>
- 执行结果
自定义标签 simpletag
- 与自定义过滤器区别,可以接受更多参数,使用标签引用{{% %}
与自定义filter类似(也是在python包的templatetags文件下,创建此标签),只不过接收更灵活的参数。 #simple_tag 代码 @register.simple_tag(name="plus") def plus(a, b, c): return "{} + {} + {}".format(a, b, c) #使用simple tag 自定义标签 {% load app01_demo %} {# simple tag #} {% plus "1" "2" "abc" %} #例子 标签代码 @register.simple_tag def join_str(*args, **kwargs): return '{} - {} '.format('*'.join(args), '$'.join(kwargs.values())) # 模板 {% load my_tags %} {% join_str '1' '2' '钢蛋' k1='3' k2='4' %}
- 执行效果
自定义标签 inclusion_tag
多用于返回html代码片段 (动态变量 分页)
app文件下 创建python包
包文件名必须为 templatetags
在templatetags里面创建任意 .py 文件
写函数
-
html页面代码
#分页显示代码 <nav aria-label="page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="previous"> <span aria-hidden="true">«</span> </a> </li> {% for i in num %} <li><a href="#">{{ i }}</a></li> {% endfor %} <li> <a href="#" aria-label="next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> #页面1 {% load my_tags %} {% page 5 %} #页面2 {% load my_tags %} {% page 1 %}
显示效果
总结:
自定义过滤器 filter 只能接受两个参数 调用的时候使用 {{ filter }} 自定义标签 simpletag 与自定义过滤器区别,可以接受更多参数,使用标签引用{{% %} 自定义标签 inclusion_tag 多用于返回html代码片段,使用标签引用{{% %}
csrf_token 跨站请求伪造保护
在页面的form表单里面写上{% csrf_token %}
- 如图
静态文件相关
#作用 在配置文件找到静态文件别名,与文件地址进行拼接,这样别名改了,也不会影响,静态文件的导入 {% load static %} <img src="{% static "images/hi.jpg" %}" alt="hi!" /> #引用js文件时使用: {% load static %} <script src="{% static "mytest.js" %}"></script> #某个文件多处被用到可以存为一个变量 {% load static %} {% static "images/hi.jpg" as myphoto %} <img src="{{ myphoto }}"></img> {% load static %} <link rel="stylesheet" href="{% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %}"> <link rel="stylesheet" href="{% static '/css/dsb.css' %}"> {% static '/plugins/bootstrap-3.3.7/css/bootstrap.css' %} {% get_static_prefix %} # 获取别名
- 获取配置文件的 别名
母版和继承
什么是母版?
普通的html页面 母版页用于处理html页面相同部分内容,避免出现冗余代码,减少重复html页面的编写,提高代码复用性,方便代码修改.
继承写法
#在子页面中在页面最上方使用下面的语法来继承母板。 {% extends '母版文件名.html' %}
block 块
通过在母板中使用{% block xxx %}来定义"块"。 在子页面中通过定义母板中的block名来对应替换母板中相应的内容。 #定义block {{% block 块名 %}} {{% endblock %}}
子页面替换母版 block块
- 注意事项
注意的点: 1. {% extends 'base.html' %} 写在第一行 前面不要有内容 有内容会显示 2. {% extends 'base.html' %} 'base.html' 加上引号 不然当做变量去查找 3. 把要显示的内容写在block块中 4. 定义多个block块,定义 css js 块
组件
#作用 可以将常用的页面内容如导航条,页尾信息等组件保存在单独的文件中,然后在需要使用的地方按如下语法导入即可。 #示列 单独建一个html page <nav aria-label="page navigation"> <ul class="pagination"> <li> <a href="#" aria-label="previous"> <span aria-hidden="true">«</span> </a> </li> {% for i in num %} <li><a href="#">{{ i }}</a></li> {% endfor %} <li> <a href="#" aria-label="next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav> #别的页面 引用 {% include 'page.html' %}