模板
-
1. 模板的功能
产生html,控制页面上展示的内容。模板文件不仅仅是一个html文件。
模板文件包含两部分内容:
1) 静态内容:css,js,html。
2) 动态内容:用于动态去产生一些网页内容。通过模板语言来产生。
-
2. 模板文件的使用
通常是在视图函数中使用模板产生html内容返回给客户端。
a) 加载模板文件 loader.get_template
获取模板文件的内容,产生一个模板对象。
b) 定义模板上下文 RequeseContext
给模板文件传递数据。
c) 模板渲染产生html页面内容 render
用传递的数据替换相应的变量,产生一个替换后的标准的html内容。
1 from django.shortcuts import render 2 from django.template import loader,RequestContext 3 from django.http import HttpResponse 4 5 # Create your views here. 6 7 def My_render(request,template_path,context={}): 8 # 1、加载模板文件,获取模板对象 9 temp = loader.get_template(template_path) 10 # 2、定义模板上下文,给模板文件传递数据 11 context = RequestContext(request,context) 12 context.push(locals()) 13 # 3、模板渲染,产生一个替换后的html内容 14 res_html = temp.render(context=locals(), request=request) 15 # 4、返回应答 16 return HttpResponse(res_html) 17 18 def index(request): 19 ## 调用My_render 20 # return My_render(request,'booktest/index.html') 21 22 ## 上面的4个步骤django已经封装好了,直接调用就可以了 23 return render(request,'booktest/index.html')
-
3. 模板文件加载顺序
1) 首先去配置的模板目录下面去找模板文件。
2) 去INSTALLED_APPS下面的每个应用的templates去找模板文件,前提是应用中必须有templates文件夹。
-
4. 模板语言
模板语言简称为DTL。(Django Template Language)
4.1 模板变量
模板变量名是由数字,字母,下划线和点组成的,不能以下划线开头。
使用模板变量:{{模板变量名}}
模板变量的解析顺序:
例如:{{ book.btitle }}
1) 首先把book当成一个字典,把btitle当成键名,进行取值book['btitle']
2) 把book当成一个对象,把btitle当成属性,进行取值book.btitle
3) 把book当成一个对象,把btitle当成对象的方法,进行取值book.btitle
例如:{{book.0}}
1) 首先把book当成一个字典,把0当成键名,进行取值book[0]
2) 把book当成一个列表,把0当成下标,进行取值book[0]
如果解析失败,则产生内容时用空字符串填充模板变量。
使用模板变量时,.前面的可能是一个字典,可能是一个对象,还可能是一个列表。
1 from django.shortcuts import render 2 from django.template import loader,RequestContext 3 from django.http import HttpResponse 4 from booktest.models import BookInfo 5 6 7 def temp_var(request): 8 '''模板变量''' 9 dict = {'key':'这是一个字典key值'} 10 list = ['元素1','元素2','元素3'] 11 book = BookInfo.objects.get(id=4) 12 context = {'dict':dict,'list':list,'book':book} 13 return render(request,'booktest/temp_var.html',context)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <p>字典:{{ dict.key }}</p> <p>列表:{{ list.1 }}</p> <p>属性:{{book}}</p> </body> </html>
4.2 模板标签
{% 代码段 %}
for循环:
{% for x in 列表 %}
# 列表不为空时执行
{% empty %}
# 列表为空时执行
{% endfor %}
可以通过{{ forloop.counter }}得到for循环遍历到了第几次。
{% if 条件 %}
{% elif 条件 %}
{% else %}
{% endif %}
关系比较操作符:> < >= <= == !=
注意:进行比较操作时,比较操作符两边必须有空格。
逻辑运算:not and or
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf8"> <title>temp_tags</title> <style> .red{ background:red; } .yellow{ background:yellow; } .green{ background:green; } </style> </head> <body> <ul> {% for book in books %} <!--加入判断条件--> {% if book.id < 5 %} <li class="red"> {{ forloop.counter }}--{{ book.btitle }} </li> {% elif book.id < 10 %} <li class="yellow"> {{ forloop.counter }}--{{ book.btitle }} </li> {% else %} <li class="green"> {{ forloop.counter }}--{{ book.btitle }} </li> {% endif %} {% endfor %} </ul> </body> </html>
4.3 过滤器
过滤器用于对模板变量进行操作。
date:改变日期的显示格式。
length:求长度。字符串,列表.
default:设置模板变量的默认值。
格式:模板变量|过滤器:参数
自定义过滤器。
自定义的过滤器函数,至少有一个参数,最多两个
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf8"> <title>temp_filter</title> <style> .red{ background:red; } .yellow{ background:yellow; } .green{ background:green; } </style> </head> <body> <ul> {% for book in books %} <!--加入判断条件--> {% if book.id < 5 %} <li class="red"> {{ book.btitle }}--{{ book.bpub_date|date:"Y年-m月-d日" }} </li> {% elif book.id < 10 %} <li class="yellow"> {{ book.btitle }}--{{ book.bpub_date }} </li> {% else %} <li class="green"> {{ book.btitle }}--{{ book.bpub_date }} </li> {% endif %} {% endfor %} </ul> </body> </html>
参考资料:(模板标签和内置过滤器)
http://python.usyiyi.cn/documents/django_182/ref/templates/builtins.html
4.4 模板注释
单行注释:{# 注释内容 #}
多行注释:
{% comment %}
注释内容
{% endcomment %}
-
5. 模板继承
模板继承也是为了重用html页面内容。
在父模板里可以定义块,使用标签:
{% block 块名 %}
块中间可以写内容,也可以不写
{% endblock 块名%}
子模板去继承父模板之后,可以重写父模板中的某一块的内容。
继承格式:{% extends 父模板文件路径%}
{% block 块名 %}
{{ block.super}} #获取父模板中块的默认内容
重写的内容
{% endblock 块名%}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>{% block title %}父模板{% endblock title %}</title> </head> <body> <h1>导航条</h1> {% block a %} {# 给子模板预留位置 #} <h1>这是父模板的信息</h1> {% endblock a %} <h1>版权信息</h1> </body> </html>
{% extends 'booktest/base.html' %} {% block title %}子模板{% endblock title %} {% block a %} {# 继承父模板,重写块 #} {{ block.super }} <h1>这是子模板的信息</h1> {% endblock a %}
-
6. html转义
在模板上下文中的html标记默认是会被转义的。
小于号< 转换为<
大于号> 转换为>
单引号' 转换为'
双引号" 转换为 "
与符号& 转换为 &
要关闭模板上下文字符串的转义:可以使用 {{ 模板变量|safe}}
也可以使用:
{% autoescape off %}
模板语言代码
{% endautoescape %}
模板硬编码中的字符串默认不会经过转义,如果需要转义,那需要手动进行转义。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>模板转义</title> </head> <p>没有进行转义:{{ context }}</p> <p>使用过滤器safe关闭转义:{{ context|safe }}</p> <p>使用autoescape关闭转义:</p> {% autoescape off %} {{ context }} {% endautoescape %} <p>模板硬编码默认会进行转义:</p> {{ test|default:'<h1>硬编码</h1>' }} <p>关闭模板硬编码默认转义:</p> {{ test|default:'<h1>硬编码<h1>' }} </body> </html>
-
7. csrf攻击
首先做一个登录页,让用户输入用户名和密码进行登录,登录成功之后跳转的修改密码页面。在修改密码页面输入新密码,点击确认按钮完成密码修改。
登录页需要一个模板文件login.html.修改密码页面也需要一个模板文件change_pwd.html.
显示登录页的视图login,验证登录的视图login_check,显示发帖页的视图change_pwd,处理修改密码的视图change_pwd_action.
加功能:
a)只有用户登录之后才可以进行修改密码操作。
登录装饰器函数。
案例流程图:
CSRF攻击原理
CSRF:跨站请求伪造
- 用户访问一个正常网站例如www.baidu.com,假如用户通过post提交用户信息,服务器设置了session,会发一个sessionid给浏览器保存
- 用户又访问了攻击者构造的恶意网站
- 恶意网站可以让用户自动提交一个请求到目标网站(www.baidu.com),这个时候恶意网站就会将浏览器保存的sessionid发过去服务器,从而修改服务器里保存的用户信息
- 提交请求的操作不是恶意网站发起的而是恶意网站让用户发起的
django防止csrf的方式:
1) 默认打开csrf中间件。
2) 表单post提交数据时加上{% csrf_token %}标签。
防御原理:
1) 渲染模板文件时在页面生成一个名字叫做csrfmiddlewaretoken的隐藏域。
2) 服务器交给浏览器保存一个名字为csrftoken的cookie信息。
3) 提交表单时,两个值都会发给服务器,服务器进行比对,如果一样,则csrf验证通过,否则失败。
-
8. 验证码
在用户注册、登录页面,为了防止暴力请求,可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻业务服务器、数据库服务器的压力。
1 from PIL import Image, ImageDraw, ImageFont 2 from django.utils.six import BytesIO 3 4 5 # /verify_code 6 def verify_code(request): 7 # 引入随机函数模块 8 import random 9 # 定义变量,用于画面的背景色、宽、高 RGB 10 bgcolor = (random.randrange(20, 100), random.randrange( 11 20, 100), 255) 12 width = 100 13 height = 25 14 # 创建画面对象 15 im = Image.new('RGB', (width, height), bgcolor) 16 # 创建画笔对象 17 draw = ImageDraw.Draw(im) 18 # 调用画笔的point()函数绘制噪点 19 for i in range(0, 500): 20 xy = (random.randrange(0, width), random.randrange(0, height)) 21 fill = (random.randrange(0, 255), 255, random.randrange(0, 255)) 22 draw.point(xy, fill=fill) 23 24 # 定义验证码的备选值 25 str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0' 26 # 随机选取4个值作为验证码 27 rand_str = '' 28 for i in range(0, 4): 29 rand_str += str1[random.randrange(0, len(str1))] 30 31 # 构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont” 32 font = ImageFont.truetype('static/font/verdana.ttf', 23) 33 # 构造字体颜色 34 fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255)) 35 # 绘制4个字 36 draw.text((5, 2), rand_str[0], font=font, fill=fontcolor) 37 draw.text((25, 2), rand_str[1], font=font, fill=fontcolor) 38 draw.text((50, 2), rand_str[2], font=font, fill=fontcolor) 39 draw.text((75, 2), rand_str[3], font=font, fill=fontcolor) 40 # 释放画笔 41 del draw 42 # 存入session,用于做进一步验证 43 request.session['verifycode'] = rand_str 44 # 内存文件操作 45 buf = BytesIO() 46 # 将图片保存在内存中,文件类型为png 47 im.save(buf, 'png') 48 # 将内存中的图片数据返回给客户端,MIME类型为图片png 49 return HttpResponse(buf.getvalue(), 'image/png')
-
9. 反向解析
当某一个url配置的地址发生变化时,页面上使用反向解析生成地址的位置不需要发生变化。
根据url 正则表达式的配置动态的生成url。
在项目urls中包含具体应用的urls文件时指定namespace;
urlpatterns = [ path('admin/', admin.site.urls), url(r'^',include(('booktest.urls','booktest'),namespace='booktest')), ]
在应用的urls中配置是指定name;
from django.conf.urls import url from booktest import views urlpatterns = [ url(r'^index$',views.index,name='index'), url(r'^url_reverse$',views.url_reverse),## url反向解析 url(r'^show_args/(d+)/(d+)',views.show_args,name='show_args'),## 动态捕获位置参数 url(r'^show_kwargs/(?P<c>d+)/(?P<d>d+)',views.show_kwargs,name='show_kwargs'),## 捕获关键字参数 url(r'^test_reverse$',views.test_reverse),## 视图函数重定向 ]
(1)在模板文件中使用时,格式如下:
{% url 'namespace名字:name' %} 例如{% url 'booktest:fan2'%}
带位置参数:
{% url 'namespace名字:name' 参数 %} 例如{% url 'booktest:fan2' 1%}
带关键字参数:
{% url 'namespace名字:name' 关键字参数 %} 例如{% url 'booktest:fan2' id=1 %}
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>url反向解析</title> </head> <body> index链接:</br> <a href="/index">首页</a></br> <p>使用url反向解析获取/index链接</p> <a href="{% url 'booktest:index' %}">首页</a> <p>访问/show_args/1/2:</p> <p><a href="/show_args/1/2">show_args/1/2</a></p> <p>动态生成/show_args/1/2</p> <p><a href="{% url 'booktest:show_args' 1 2 %}">show_args/1/2</a></p> <p>访问show_kwargs/1/2:</p> <p><a href="show_kwargs/1/2">show_kwargs/1/2</a></p> <p>动态生成show_kwargs/1/2:</p> <p><a href="{% url 'booktest:show_kwargs' c=1 d=2 %}">show_kwargs/1/2</a></p> </body> </html>
(2)视图函数,在重定向的时候使用反向解析:
from django.core.urlresolvers import reverse(django更新之后是:
from django.urls import reverse
)
无参数:
reverse('namespace名字:name名字')
如果有位置参数
reverse('namespace名字:name名字', args = 位置参数元组)
如果有关键字参数
reverse('namespace名字:name名字', kwargs=字典)
1 from django.urls import reverse 2 def test_reverse(request): 3 '''重定向跳转''' 4 ## 重定向到/index 5 # url = reverse('booktest:index') 6 7 ## 重定向到/show_args/1/2 8 # url = reverse('booktest:show_args',args=(1,2)) 9 10 ## 重定向到/show_kwargs/3/4 11 url = reverse('booktest:show_kwargs',kwargs={'c':3,'d':4}) 12 return redirect(url)