一、模板的功能
产生html,控制页面上展示的内容。模板文件不仅仅是一个html文件。
模板文件包含两部分内容:
1)静态内容:css,js,html;
2)动态内容:用于动态去产生一些网页内容。通过模板语言来产生。
二、模板文件的使用
通常是在视图函数中使用模板产生html内容返回给客户端。
a)加载模板文件 loader.get_template
获取模板文件的内容,产生一个模板对象
b)定义模板上下文 RequeseContext
给模板文件传递数据。
c)模板渲染产生html页面内容render
用传递的数据替换相应的变量,产生一个替换后的表中html内容。
from django.shortcuts import render
from django.template import loader, RequestContext
from django.http import HttpResponse
# Create your views here.
def my_render(request, template_path, context={}):
# 1.加载模板文件,获取一个模板对象
temp = loader.get_template(template_path)
# 2.定义模板上下文,给模板文件传数据
context = RequestContext(request, context)
context.push(locals())
# 3.模板渲染,产生一个替换后的html内容
res_html = temp.render(context=locals(), request=request)
# 4.返回应答
return HttpResponse(res_html)
# /index
def index(request):
# return my_render(request, 'xm20200504/index.html')
return render(request, 'xm20200504/index.html')
三、模板文件加载顺序
1)首先去配置的模板目录下面去找模板文件
2)去settings.py里面INSTALLED_APPS下面的每个应用去找模板文件,前提是应用中必须有templates文件夹
四、模板语言
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]
如果解析失败,则产生内容时用空字符串填充模板变量
2、模板标签
{% 代码段 %}
for循环:
{% for x in 列表 %}
#列表不为空时执行
{% empty %}
#列表为空时执行
{% endfor %}
可以通过{{ forloop.counter }}得到for循环遍历到了第几次。
{% if条件 %}
{% elif条件 %}
{% else %}
{% endif %}
3、过滤器
过滤器用于对模板变量进行操作。
date:改变日期的显示格式
length:求长度。字符串,列表,元组,字典长度
default:设置模板变量的默认值
格式:模板变量 | 过滤器:参数
参考资料:https://blog.csdn.net/lengfengyuyu/article/details/83342639
自定义过滤器
自定义的过滤器函数,至少有一个参数,最多两个。
操作:在应用下新建python包,固定命名为templatetags,在该包下面创建python文件,自定义命名,编辑内容例如:
# 自定义过滤器
# 过滤器其实就是python函数
from django.template import Library
# 创建一个Library类的对象
register = Library()
# 自定义的过滤器函数,至少有一个参数,最多两个
@register.filter
def mod(num):
'''判断num是否为偶数'''
return num%2 == 0
@register.filter
def mod_val(num, val):
'''判断num是否能被整除'''
return num%val == 0
在前端页面需要将自定义过滤器的文件加载过来,在模板html中的head标签上添加命令
{% load 自定义过滤器python文件的命名名称 %}
另外,在html中编辑如下代码进行数据过滤
{% if book.id|mod %}
{% if book.id|mod_val:2 %}
4、模板注释
单行注释: {# 注释内容 #}
多行注释: {% comment %}
注释内容
{% endcomment %}
五、模板继承
子模板要继承父模板的所有内容,重用html页面内容,新建个html文件,使用extends关键字编辑代码即可。
{% extends '父模板html文件路径(包含html文件名称)' %}
{% extends 'booktest/base.html' %}
通常情况下,子模板继承父模板的内容作为自身部分内容,还有一些其他内容要通过子模板页面显示出来,就需要在父模板上面编写预留块,这个预留块就可以在子模板上重写,父模板格式如下:
{% block b1 %}
<h1>这是父模板b1块中的内容</h1>
{% endblock b1 %}
子模板格式如下:
{% block b1 %}
{{ block.super }} # 这句可以继承父模板预留块中内容过来
<h1>这是子模板b1块中的内容</h1>
{% endblock b1 %}
这样当访问子模板页面时就会将父模板的预留块替换掉显示出来。
六、html转义
在模板上下文中的html标记默认是会被转义的。比如
小于号< 转换为<
大于号> 转换为>
单引号' 转换为'
双引号" 转换为"
与符号& 转换为&
要关闭模板上下文字符串的转义,可以使用{{ 模板变量|safe }}
也可以使用:
{% autoescape off %}
模板语言代码
{% endautoescape off %}
模板硬编码中的字符串默认不会经过转义,如果需要转义,需要手动进行转义,如:
{{ test|default:'<h1>hello</h1>' }}
手动进行转义:
{{ test|default:'<h1>hello</h1>' }}
七、登录装饰器
在用户处于未登录状态时,用户访问login之外的其他页面时会自动跳转到登录页面,做成这种效果就需要在视图views中创建登录装饰器函数,另外在需要通过登录后才能访问的函数之前添加@装饰器函数名称。
from django.shortcuts import render, redirect
def login_required(view_func):
'''登录判断装饰器'''
def wrapper(request, *view_args, **view_kwargs):
# 判断用户是否登录
if request.session.has_key('islogin'):
# 用户已登录,调用对应的视图
return view_func(request, *view_args, **view_kwargs)
else:
# 用户未登录,跳转到登录页
return redirect('/login')
return wrapper
@login_required
def change_pwd(request):
'''显示修改密码页面'''
return render(request, 'xm20200504/change_pwd.html')
八、csrf(跨站请求)攻击
1、csrf伪造与防护
当我们注释掉settings.py中第47行的’django.middleware.csrf.CsrfViewMiddleware’时容易发生csrf伪造。我们在访问自己网站修改密码时候没有及时退出账号,再继续通过访问其他第三方网站页面时,如果点击到了其他按钮或图片,可能会通过表单提交到我们网站进行密码伪造。
当我们取消注释’django.middleware.csrf.CsrfViewMiddleware’时则会出现自己网站表单提交跳转时报403错误,只针对post提交,可以在我们的表单页面加上{% csrf_token %}进行解决
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>登陆页面</title>
</head>
<body>
<form method="post" action="/login_check">
{% csrf_token %}
用户名:<input type="text" name="username" value="{{ username }}"><br/>
密码:<input type="password" name="password"><br/>
<input type="checkbox" name="remember">记住用户名<br/>
<input type="submit" value="登陆">
</form>
</body>
</html>
防护原理:
1)渲染模板文件时在页面生成一个名字叫做csrfmiddlewaretoken的隐藏域;
2)服务器交给浏览器保存一个名字为csrftoken的cookie信息;
3)提交表单时,两个值都会发给服务器,服务器进行比对,如果一样,则csrf验证通过,否则失败。
九、验证码
在用户注册、登录页面,为了防止暴力请求,可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻业务服务器、数据库服务器的压力。
#引入绘图模块
from PIL import Image, ImageDraw, ImageFont
#引入随机函数模块
import random
# /verify_code
def verify_code(request):
#定义变量,用于画面的背景色、宽、高
bgcolor = (random.randrange(20, 100), random.randrange(20, 100), random.randrange(20, 100))
width = 100
height = 50
#创建画面对象
im = Image.new('RGB', (width, height), bgcolor)
#创建画笔对象
draw = ImageDraw.Draw(im)
#调用画笔的point()函数绘制噪点
for i in range(0, 100):
xy = (random.randrange(0, width), random.randrange(0, height))
fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
draw.point(xy, fill=fill)
#定义验证码的备选值
str = '1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
#随机选取4个值作为验证码
rand_str = ''
for i in range(0, 4):
rand_str += str[random.randrange(0, len(str))]
#构造字体对象
# font = ImageFont.truetype('楷体', 40)
#构造字体颜色
fontcolor1 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor2 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor3 = (255, random.randrange(0, 255), random.randrange(0, 255))
fontcolor4 = (255, random.randrange(0, 255), random.randrange(0, 255))
#绘制4个字
draw.text((5, 2), rand_str[0], fill=fontcolor1)
draw.text((25, 2), rand_str[1], fill=fontcolor2)
draw.text((50, 2), rand_str[2], fill=fontcolor3)
draw.text((75, 2), rand_str[3], fill=fontcolor4)
#释放画笔
del draw
# 存入session,用于做进一步验证
request.session['verifycode'] = rand_str
#内存文件操作
import io
buf = io.BytesIO()
#将图片保存在内存中,文件类型为png
im.save(buf, 'png')
#将内存中的图片数据返回给客户端,MIME类型为图片png
return HttpResponse(buf.getvalue(), 'image/png')
十、url反向解析
当某一个url配置的地址发生变化时,页面上使用反向解析生成地址的位置不需要发生变化。
根据url正则表达式的配置动态的生成url。
在项目urls中包含具体应用的urls文件时指定namespace
urlpatterns = [
path('admin/', admin.site.urls),
url(r'^', include('yy20200504.urls', namespace='yy20200504')),
]
在应用的urls中配置指定name
urlpatterns = [
url(r'^index/$', views.index, name='index'),
url(r'^index2/$', views.index2, name='index2'),
]
在模板文件中使用时,格式如下:
{% url 'namespace名字:name' %}
带位置参数:
{% url 'namespace名字:name' 参数值 %}
带关键字参数:
{% url 'namespace名字:name' 关键字参数=参数值 %}
在视图views.py重定向的时候使用反向解析:
from django.core.urlresolvers import reverse
无参数:
reverse('namespace名字:name名字')
如果有位置参数:
reverse('namespace名字:name名字', args = 位置参数元组)
如果有关键字参数:
reverse('namespace名字:name名字', kwargs = 字典)