模版层介绍
一、模版简介
1、为什么不直接将HTML编码到视图层?
- 对页面设计进行的任何改变都必须对 Python 代码进行相应的修改。
- 站点设计的修改往往比底层 Python 代码的修改要频繁得多,
- 因此如果可以在不进行 Python 代码修改的情况下变更设计,那将会方便得多。
- Python 代码编写和 HTML 设计是两项不同的工作,大多数专业的网站开发环境都将他们分配给不同的人员(甚至不同部门)来完成。
- 设计者和HTML/CSS的编码人员不应该被要求去编辑Python的代码来完成他们的工作。
- 程序员编写 Python代码和设计人员制作模板两项工作同时进行的效率是最高的,
- 远胜于让一个人等待另一个人完成对某个既包含 Python又包含 HTML 的文件的编辑工作。
基于上面所述的原因,我们将页面的设计和python代码分离开,会使得项目更干净、更容易维护。
我们使用django的模版系统 (Template System)来实现这种模式
2、python的模版使用方式:
- HTML代码+模版语法
def current_time(req):
# ================================原始的视图函数
# import datetime
# now=datetime.datetime.now()
# html="<html><body>现在时刻:<h1>%s.</h1></body></html>" %now
# ================================django模板修改的视图函数
# 方式一
# from django.template import Template,Context
# now=datetime.datetime.now()
# t=Template('<html><body>现在时刻是:<h1>{{current_date}}</h1></body></html>')
# #t=get_template('current_datetime.html')
# c=Context({'current_date':str(now)})
# html=t.render(c) # html是渲染后的字符串
#
# return HttpResponse(html)
#方式二:(推荐使用)
import datetime
now=datetime.datetime.now()
return render(request, 'current_datetime.html', {'current_date':str(now)})
3、模版语法重点:
变量相关:{{ 变量名 }}
1、深度查询,用句点符
2、过滤器
逻辑相关(标签):{{% %}}
4、注释
# 1、模版语法的注释:
{# 模板语法的注释 #}
# 2、前端注释:
<!--
前端html的注释
-->
二、模版语法之变量
DTL:Django Template Language
1、模版中使用{{python变量}}
视图层view.py :
from django.shortcuts import render, HttpResponse
from django.utils.safestring import mark_safe
def index(request):
num = 10
ss = 'hello world'
b = False
ll = [1, 2, 3,4]
dic = {'name': 'cc', 'age': 18}
def test():
print('我是test')
return 'test函数'
class People():
def __init__(self, name):
self.name = name
def print_name(self):
return self.name
def __str__(self):
return self.name
p=People('cc')
# return render(request, 'index.html',{'num':num,'ss':ss,'b':b}) # 一个一个往字典中写key:value
#locals() 把当前作用域下所有的变量,都传到context字典中
return render(request, 'index.html',locals())
index.html中:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ss}}</title>
</head>
<body>
<h1>模版语法之变量</h1>
<p>数字:{{ num }}</p>
<p>字符串:{{ ss }}</p>
<p>布尔:{{ b }}</p>
<p>列表:{{ ll }}</p>
<p>字典:{{ dic }}</p>
<p>函数:{{ test }}</p>
<p>对象:{{ p }}</p>
</body>
</html>
三、模版语法之深度查询句点符
view.py
from django.shortcuts import render, HttpResponse
from django.utils.safestring import mark_safe
def index(request):
num = 10
ss = 'hello world'
b = False
ll = [1, 2, 3, {'name':"cc"}]
dic = {'name': 'cc', 'age': 18}
def test():
print('我是test')
return 'test函数'
class People():
def __init__(self, name):
self.name = name
def print_name(self):
return self.name
def __str__(self):
return self.name
p1=People('cc')
link1 = '<a href-"https://www.baidu.com">点我<a>'
link2 = mark_safe(link1)
input_1 = '<p>用户名:<input type="text" name="name"></p>'
input_2 = mark_safe(input_1)
script_1='''
<script>
alert('你被攻击了')
</script>
'''
script_2 = mark_safe(script_1)
return render(request, 'index.html',locals())
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ ss }}</title>
</head>
<body>
<h1>模板语法之句点符的深度查询</h1>
<p>列表的第一个元素:{{ ll.1 }}</p>
<p>字典的name对应的值:{{ dic.name }}</p>
<p>列表的第三个元素的name对应的值:{{ ll.3.name }}</p>
<p>函数执行,直接写函数名即可:{{ test }}</p>
<p>函数如果有参数?不支持</p>
<p>对象调用方法: {{ p1.print_name }}</p>
<p>对象调用属性: {{ p1.name }}</p>
<hr>
<a href="https://www.baidu.com">点我</a>
<p>a标签的字符串: {{ link1 }}</p>
<p>a标签的字符串,显示成a标签: {{ link2 }}</p>
<p>用户名:<input type="text" name="name"></p>
<p>input标签:{{ input_1 }}</p>
<p>input标签,显示成标签:{{ input_2 }}</p>
<p>js原封不动显示:{{ script_1 }}</p>
{{ script_2 }}
</body>
</html>
四、模版渲染成标签还是原封不动的字符串
- xss攻击是什么?
XSS攻击通常指的是通过利用网页开发时留下的漏洞,通过巧妙的方法注入恶意指令代码到网页,
使用户加载并执行攻击者恶意制造的网页程序。这些恶意网页程序通常是JavaScript,
但实际上也可以包括Java、 VBScript、ActiveX、 Flash 或者甚至是普通的HTML。
攻击成功后,攻击者可能得到包括但不限于更高的权限(如执行一些操作)、私密网页内容、会话和cookie等各种内容
-
django是如何处理xss攻击的,原理是什么?
# 1、后台视图或者模板中导入escape方法 from django.utils.html import escape # 2、前端html页面中,对可能会出现攻击的字段增加escape过滤 示例: {{ user.username|escape }}
五、过滤器
语法:
# 1、
{{ 参数1|过滤器名称[:参数2] }}
# 过滤器最多传两个值,最少一个,(参数1可以是变量名或者变量值,参数2必须是字符串形式的)
# 示例:
{{ "hello world"|slice:'2:3'}}
# 2、链式调用:上一个过滤器的结果继续被下一个过滤器处理
{{ 变量名|过滤器1|过滤器2 }}
1、常用内置过滤器
- default
{{ num|default:'nothing' }}
# num如果是False或者空或者None,使用default后设置成指定值
- default_if_none
{{ value|default_if_none:"None..." }}
# 作用:如果只针对value是None这一种情况来设置默认值,需要使用
# 只有在value=None的情况下,才会输出“None...”
- length
{{ dic|length }}
# 返回变量的长度,参数1可以直接写值如:{"k1":111, "k2":222}
# 对字符串、列表、字典等容器类型都起作用
- filesizeformat
{{ num|filesizeformat }}
# 将一个值格式化为一个可读的文件尺寸(如:16KB、3.5GB等)
- date
{{ value|date:"Y-m-d H:i:s"}}
# 作用:将日期按照指定的格式输出 value可以是 datetime.datetime.now()
- slice
{{ value|slice:"0:2"}}
# 作用:对输出的字符串进行切片操作,顾头不顾尾
- truncatechars
{{ value|truncatechars:8 }}
# 作用:如果字符串多于指定的字符数量,那么将会被截断,截断的字符串将以...结尾,
# 注意:8个字符串中也包括"..."
- truncatewords
{{ value|truncatewords:2}}
# 作用与truncatechars差不多,但是truncatewords是按照单词截断的、
# 并且末尾的...不能算作单词
- safe
{{ link1|safe }}
# 作用:经过过滤器safe的处理,浏览器在进行解析时就会把link1当做超链接,不加safe过滤器就会当做普通字符显示
六、模版语法之标签
标签看起来像是这样的: {% tag %}。
标签比变量更加复杂:一些在输出中创建文本,一些通过循环或逻辑来控制流程,一些加载其后的变量将使用到的额外信息到模版中。一些标签需要开始和结束标签 (例如{% tag %} ...标签 内容 ... {% endtag %})
1、常用标签
- for标签
# for的用法
# 示例一:
{% for l in ll %}
<p>
<a href="http://127.0.0.1:8080/{{ l }}">{{ l }}</a>
</p>
{% endfor %}
# 示例二:
{% for k,v in dic.items %}
<p>key值:{{ k }}, value值:{{ v }}</p>
{% endfor %}
# 示例三:
<table border="1">
<tr>
<td>id号</td>
<td>用户名</td>
<td>年龄</td>
</tr>
{% for dic in user_list %}
<tr>
<td>{{ forloop.counter }}</td>
<td>{{ dic.name }}</td>
<td>{{ dic.age }}</td>
</tr>
{% endfor %}
</table>
# 在for标签内部一直有一个forloop对象,是一个字典
{'parentloop': {}, 'counter0': 0, 'counter': 1, 'revcounter': 6, 'revcounter0': 5, 'first': True, 'last': False}
- forloop.counter0:从0开始,每循环一次加1
- forloop.counter:从1开始,每循环一次加1
- forloop.revcounter:从列表长度开始,每循环一次减一
- forloop.first:判断是不是循环的第一个
- forloop.last:判断是不是循环的最后一个
- forloop.parentloop:父级forloop对象,本层循环的外层循环(for循环嵌套)
- for…empty
<ul>
{% for l in ll %}
<li>{{ l }}</li>
{% empty %}
<li>nothing</li>
{% endfor %}
</ul>
# 当列表ll中为空时,将在浏览器中显示指定的“nothing”
- if标签
{% if b %}
<p>b是True</p>
{% else %}
<p>b是False</p>
{% endif %}
# 条件判断,if语句支持 and 、or、==、>、<、!=、<=、>=、in、not in、is、is not判断
# 也支持if...elif...else...endif
- with
{% with forloop.parentloop.counter as aaa %}
{{ aaa }}
{% endwith %}
# 作用:给xxx变量起别名,则下面可以使用别名访问值
- csrf_token
{% csrf_token %}
# 作用:这个标签用于跨站请求伪造保护
# 用法:在html页面的form表单中写上{% csrf_token %}
2、注意事项
# 1、django的模板语言不支持连续判断,即不支持{% if a>b>c %}...{% endif %}
# 2、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的value值100
七、自定义标签与过滤器
1、自定义过滤器
# 步骤:
(1) 在settings中的INSTALLED_APPS里配置当前app,否则django无法找到自定义的simple_tag
(2) 在app中创建templatetags模块(模块名不能改,只能叫templatetags)
(3) 在模块内新建.py文件(如:my_tags.py)
(4) 写代码(过滤器)
from django import template
register = template.Library()
@register.filter
def my_upper(value):
return value.upper()
(5) 模板中使用:先load,再使用
{% load my_tags %}
{{ 'aa'|my_upper }}
2、自定义标签
(1) 在settings中的INSTALLED_APPS里配置当前app
(2) 在app中创建templatetags模块
(3) 在模块内新建.py文件(如:my_tags.py)
(4) 写代码(标签)
from django import template
from django.utils.safestring import mark_safe
register = template.Library()
@register.simple_tag
def my_csrf():
import uuid
res = uuid.uuid(4)
return mark_safe('<input type="hidden" name="csrfmiddlewaretoken" value="%s">'%res)
(5) 模板中使用:先load,再使用
{% load my_tags %}
{% my_csrf %}
{% my_tag 111 222 333 %} # 如果my_tag函数需要多个参数,那么直接加载后面
八、模板的导入与继承
1、模板的导入
(1)第一步:新建一个xxx.html,把模板写入:
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">重金求子</h3>
</div>
<div class="panel-body">
详情点击:<a href="http://www.baidu.com">疯狂点我</a>
</div>
</div>
(2)第二步:在需要使用的地方导入
{% include "xxx.html" %}
2、模板的继承(母版)
(1) 第一步:写一个母版,在母版里面写空盒子
{% block top %}
{% endblock %}
(2) 第二步:某个页面如果要使用母版,就先引入,再扩写盒子
{% extends "base.html" %}
{% block top %}
index页面
{% endblock %}
九、静态文件相关
有三种设置方式:
# 第一种:
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
# 第二种:
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
# 第三种:
{% load static %}
<link rel="stylesheet" href="{% get_static_prefix %}bootstrap/css/bootstrap.min.css">
# 特殊用法:
{% load static %}
{% static "image/hi.jpg" as mypicture %}
<img src="{{ myphoto }}"></img>
{% load static %}
{% get_static_prefix as static %}
<img src="{{ static }}image/hi.jpg" alt="Hi!">
十、inclusion_tag的使用
# 可以生成一片模板中的代码块
# 使用步骤:
(1) 在settings中的INSTALLED_APPS里配置当前app
(2) 在app中创建templatetags模块
(3) 在模块内新建.py文件(如:my_tags.py)
(4) 写代码(inclusion_tag)
from django import template
register = template.Library()
@register.inclusion_tag('left.html')
def left(num):
dic = {i:'第%s页' % i for i in range(num)}
# 返回值必须是一个字典形式
return {'data': dic}
@register.inclusion_tag('popular.html')
def popular(title, url):
return {'title':title, 'url':url}
(5) 模板中使用:先load,再使用
{% load my_tags %} //先导入
{% left 5 %} //5就是参数
{% popular 'xxx名字' 'url地址' %}
- 与tag的区别:
- tag:需要在视图层代码中写html内容
- inclusion_tag:视图层代码与模板分离