一.模板
作为Web框架,Django提供了模板,用于编写html代码,还可以嵌入模板代码更快更方便的完成页面开发,再通过在视图中渲染模板,将生成最终的html字符串返回给客户端浏览器。模版致力于表达外观,而不是程序逻辑。模板的设计实现了业务逻辑view与显示内容template的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用。
1.模板包含两部分:
- 静态部分,包含html、css、js。
-
动态部分,就是模板语言。
Django模板语言,简写DTL,定义在django.template包中。 创建项目后,在"项目名称/settings.py"文件中定义了关于模板的配置。
DIRS定义一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板文件,通常是在项目的根目录下创建templates目录。
2.Django处理模板分为两个阶段:
1.加载:根据给定的路径找到模板文件,编译后放在内存中。
2.渲染:使用上下文数据对模板插值并返回生成的字符串。
为了减少开发人员重复编写加载、渲染的代码,Django提供了简写函数render,用于调用模板。
二.模板语言
1.模板语言包括4种类型,分别是:
- 变量
- 标签
- 过滤器
- 注释
三.模板变量
模板变量的作用是计算并输出,变量名必须由字母、数字、下划线(不能以下划线开头)和点组成。
语法如下:
{{变量}}
- 当模版引擎遇到点如book.title,会按照下列顺序解析:
1.字典book['title']
2.先属性后方法,将book当作对象,查找属性title,如果没有再查找方法title()
3.如果是格式为book.0则解析为列表book[0]
如果变量不存在则插入空字符串''。
在模板中调用方法时不能传递参数。
1.示例:
1.打开booktest/views.py文件,修改视图index。
- 方法一
def index(request):
dict:{'title':'Mysql从入门到放弃'}
book = BookInfo()
book.btitle='天龙八部'
return render(request,'booktest/index4.html',{'dict':dict,'book':book})
- 方法二
def index(request):
dict = {'title': 'Mysql从入门到放弃'}
book = BookInfo()
book.btitle = '天龙八部'
context = {'dict': dict, 'book': book}
return render(request, 'booktest/index4.html', context)
2.打开booktest/urls.py文件,配置url。(我们已经配置完啦)
3.修改在templates/booktest下创建index4r.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ dict.title }}<br>
{{ book.btitle }}
</body>
</html>
4.运行服务器,在浏览器中输入如下网址:http://127.0.0.1:8000/

四.标签
语法如下:
{%代码段%}
- for标签语法如下:
{%for i in 列表 %}
循环逻辑
{{ forloop.counter }} 表示当前是第几次循环,从1 开始
{% empty %}
列表为空或者不存在的时候会执行的部分
{% endfor %}
- if标签语法如下:
{% if 要判断的条件 %}
逻辑1
{% elif 要判断的条件 %}
逻辑2
{% else %}
逻辑3
{% endif %}
- 比较运算符如下:
注意:运算符左右两侧不能紧挨变量或常量,必须有空格。
==
!=
<
>
<=
>=
- 布尔运算符如下:
and
or
not
示例:
- 打开booktest/views.py文件,创建视图templates_test
from booktest.models import BookInfo
def templates_test(request):
context={'list':BookInfo.objects.all()}
return render(request,'booktest/index5.html',context)
- 打开booktest/urls.py文件,配置url。
url(r'^templates_test/$',views.templates_test),
- 在templates/booktest下创建index5.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>起点小说网图书列表</h1>
<p>图书id小于3的书背景颜色是红,小于4是蓝,其他为绿</p>
<ul>
{% for book in list %}
{% if book.id < 3 %}
<li style="background-color: red">{{ book.btitle }}</li>
{% elif book.id >= 3 and book.id <= 4 %}
<li style="background-color: blue">{{ book.btitle }}</li>
{% else %}
<li style="background-color: green">{{ book.btitle }}</li>
{% endif %}
{% empty %}
<li>对不起,所有图书都下架了</li>
{% endfor %}
</ul>
</body>
</html>
-
在这里我们修改一下数据库的数据,因为之前我们将两本书的isDelete值设为了1,所以这次我们确保isDelete的值都为0
- 运行服务器,在浏览器中输入如下网址:http://127.0.0.1:8000/templates_test/
- 如果想看 没有图书的或者不符合要求的界面是什么效果的话,将views.py文件修改成这样:
def templates_test(request):
# contest = {'list':BookInfo.books.all()}
# book = BookInfo()
contest = {}
return render(request,'booktest/index5.html',contest)
-
再次运行上面的网址:
五.过滤器
语法如下:
- 使用管道符号|来应用过滤器,用于进行计算、转换操作,可以使用在变量、标签中。
- 如果过滤器需要参数,则使用冒号:传递参数。
变量|过滤器:参数
长度length,返回字符串包含字符的个数,或列表、元组、字典的元素个数。
默认值default,如果变量不存在时则返回默认值。
data|default:'默认值'
日期date,用于对日期类型的值进行字符串格式化,常用的格式化字符如下:
- Y表示年,格式为4位,y表示两位的年。
- m表示月,格式为01,02,12等。
- d表示日, 格式为01,02等。
- j表示日,格式为1,2等。
- H表示时,24进制,h表示12进制的时。
- i表示分,为0-59。
- s表示秒,为0-59。
value|date:"Y年m月j日 H时i分s秒"
示例
- 打开booktest/views.py文件,创建视图temp_filter。
def temp_filter(request):
context = {'list': BookInfo.books.all()}
return render(request, 'booktest/temp_filter.html', context)
- 打开booktest/urls.py文件,配置url。
url(r'^temp_filter/$',views.temp_filter),
- 在templates/booktest下创建temp_filter.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>起点小说网图书列表</h1>
<p>书名大于3的变成blue-默认时间格式,其他的为red--Y-m-j</p>
<ul>
{% for book in list %}
{% if book.btitle|length > 4 %}
<li style="background-color: blue">
{{ book.btitle }}
{{ book.bpub_date }}
</li>
{% else %}
<li style="background-color: red">
{{ book.btitle }}
{{ book.bpub_date |date:"Y-M-J" }}
</li>
{% endif %}
{% empty %}
<li>对不起,所有图书都下架了</li>
{% endfor %}
</ul>
</body>
</html>
- 运行服务器,在浏览器中输入如下网址:http://127.0.0.1:8000/temp_filter/
2.自定义过滤器
过滤器就是python中的函数,注册后就可以在模板中当作过滤器使用,下面以求余为例开发一个自定义过滤器mod。
示例
- 在应用中创建templatetags目录,当前示例为"booktest/templatetags",复制init.py文件,内容为空。
- 在"booktest/templatetags"目录创建filters.py文件,代码如下:
#自定义一个过滤器
from django.template import Library
#实例化Library
register = Library()
#使用装饰器注册
@register.filter
#定义求余汉顺,将值对2求余
def mod(value):
return value%2 ==0
- 在templates/booktest/temp_filter.html中,使用自定义过滤器。
首先使用load标签引入模块。
{%load filters%}

在遍历时根据编号判断奇偶,代码改为如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
{% load filter %}
</head>
<body>
<h1>起点小说网图书列表</h1>
<p>编号为单数的时候红色,编号为双数的时候为蓝色</p>
<ul>
{% for book in list %}
{% if book.id|mod %}
<li style="background-color: blue">
{{ book.id }}
{{ book.btitle }}
{{ book.bpub_date }}
</li>
{% else %}
<li style="background-color: red">
{{ book.id }}
{{ book.btitle }}
{{ book.bpub_date |date:"Y-M-J" }}
</li>
{% endif %}
{% empty %}
<li>对不起,所有图书都下架了</li>
{% endfor %}
</ul>
</body>
</html>

-
运行服务器,浏览效果如下:
自定义过滤去至少有一个,至多有两个(有两个参数传一个)
-
定义两个参数
-
在数据库中添加一条数据
-
将num赋值成3,形式如下:
-
运行程序,编号能被3整除的显示蓝色,不能被三整除的显示红色
六.注释
在模板中使用如下模板注释,这段代码不会被编译,不会输出到客户端;html注释只能注释html内容,不能注释模板语言。
- 单行注释语法如下:
{#...#}
- 注释可以包含任何模版代码,有效的或者无效的都可以。
{# { % if foo % }bar{ % else % } #}
- 多行注释使用comment标签,语法如下:
{%comment%}
...
{%endcomment%}
七.模板继承
模板继承和类的继承含义是一样的,主要是为了提高代码重用,减轻开发人员的工作量。
典型应用:网站的头部、尾部信息。
1.父模板
如果发现在多个模板中某些内容相同,那就应该把这段内容定义到父模板中。
标签block:用于在父模板中预留区域,留给子模板填充差异性的内容,名字不能相同。 为了更好的可读性,建议给endblock标签写上名字,这个名字与对应的block名字相同。父模板中也可以使用上下文中传递过来的数据。
{%block 名称%}
预留区域,可以编写默认内容,也可以没有默认内容
{%endblock 名称%}
2.子模板
标签extends:继承,写在子模板文件的第一行。
{% extends "父模板路径"%}
子模版不用填充父模版中的所有预留区域,如果子模版没有填充,则使用父模版定义的默认值。
填充父模板中指定名称的预留区域。
{%block 名称%}
实际填充内容
{{block.super}}用于获取父模板中block的内容
{%endblock 名称%}
3.示例
- 打开booktest/views.py文件,创建视图temp_inherit。
def temp_inherit(request):
context = {'list': BookInfo.books.all()}
return render(request, 'booktest/temp_inherit.html', context)
- 打开booktest/urls.py文件,配置url。
url(r'^temp_inherit/$',views.temp_inherit),
- 在templates下创建inherit_base.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>网站头部</h1>
<hr>
{% block qu1 %}
这是区域一,里面有默认值
{% endblock qu1 %}
<hr>
{% block qu2 %}
{% endblock qu2 %}
<h1>网站footer页</h1>
</body>
</html>
- 在templates/booktest下创建temp_inherit.html。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{#继承父模板#}
{% extends 'booktest/temp_base.html' %}
{% block qu2 %}
<ul>
{% for book in list %}
<li>{{ book.btitle }}</li>
{% endfor %}
</ul>
{% endblock qu2 %}
</body>
</html>
八.CSRF
CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造。CSRF指攻击者盗用了你的身份,以你的名义发送恶意请求。CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......造成的问题包括:个人隐私泄露以及财产安全。

如果想防止CSRF,首先是重要的信息传递都采用POST方式而不是GET方式,接下来就说POST请求的攻击方式以及在Django中的避免。
-
Django项目中默认启用了csrf保护,现在先禁用,打开test3/settings.py文件,注释掉csrf中间件。
详细内容我们以后讲解
九.验证码
在用户注册、登录页面,为了防止暴力请求,可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻业务服务器、数据库服务器的压力。
1.手动实现验证码
- 安装包Pillow3.4.1。
pip install Pillow==3.4.1
在pycharm的命令行中输入即可:

- 在booktest/views.py文件中,创建视图verify_code。
提示1:随机生成字符串后存入session中,用于后续判断。
提示2:视图返回mime-type为image/png。
from PIL import Image, ImageDraw, ImageFont
from django.utils.six import BytesIO
def verify_code(request):
#引入随机函数模块
import random
#定义变量,用于画面的背景色、宽、高
bgcolor = (random.randrange(20, 100), random.randrange(
20, 100), 255)
width = 100
height = 25
#创建画面对象
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)
#定义验证码的备选值
str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
#随机选取4个值作为验证码
rand_str = ''
for i in range(0, 4):
rand_str += str1[random.randrange(0, len(str1))]
#构造字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”
font = ImageFont.truetype('FreeMono.ttf', 23)
#构造字体颜色
fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
#绘制4个字
draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)
#释放画笔
del draw
#存入session,用于做进一步验证
request.session['verifycode'] = rand_str
#内存文件操作
buf = BytesIO()
#将图片保存在内存中,文件类型为png
im.save(buf, 'png')
#将内存中的图片数据返回给客户端,MIME类型为图片png
return HttpResponse(buf.getvalue(), 'image/png')
- 打开booktest/urls.py文件,配置url。
url(r'^verify_code/$', views.verify_code),
- 将字体导入到C:\Windows\Fonts目录下
链接:https://pan.baidu.com/s/1F897AYFjrXBqS_odP1Jfzw
提取码:o5h8
字体百度云链接
- 打开浏览器页面http://127.0.0.1:8000/verify_code/
当然,如果报错的话,那你就换一个你本机拥有的字体,大多数都是因为本机字体没有导入进去导致的,所以换个字体就好啦,然后多实验几次,看看值会不会改变
2.调用验证码
- 在booktest/views.py文件中,创建视图verify_show。
def verify_show(request):
return render(request,'booktest/verify_show.html')
- 打开booktest/urls.py文件,配置url。
url(r'^verify_show/$', views.verify_show),
- 在templates/booktest/目录下创建verify_show.html。
<html>
<head>
<title>验证码</title>
</head>
<body>
<form method="post" action="/verify_yz/">
{%csrf_token%}
<input type="text" name="yzm">
<img id="yzm" src="/verify_code/"/>
<span id="change">看不清,换一个</span>
<br>
<input type="submit" value="提交">
</form>
</body>
</html>
- 运行服务器,在浏览器中输入如下网址:http://127.0.0.1:8000/verify_show/
3.验证
- 打开booktest/urls.py文件,配置url。
url(r'^verify_yz/$', views.verify_yz),
-
我们开启csrf,将之前的注释解除
- 这个时候我们需要在verify_show.html中写下一句话
{% csrf_token %}

- 在booktest/views.py文件中,创建视图verify_yz。
#验证验证码
def verify_yz(request):
#得到验证码
yzm = request.POST.get('yzm')
return HttpResponse('ok')
-
这个时候我们先验证一下:
我们点击提交:
跳出OK界面
-
如果我们将{% csrf_token %}这句话注释掉,会发生什么呢?
会出现403界面
- 在booktest/views.py文件中,修改视图verify_yz
#验证验证码(方式一)
def verify_yz(request):
#得到用户输入验证码
yzm = request.POST.get('yzm')
#从session里取出验证码
verifycode = request.session['verifycode']
if yzm == verifycode:
return HttpResponse('ok')
else:
return HttpResponse('no')
#验证验证码
def verify_yz(request):
#得到用户输入验证码
yzm = request.POST.get('yzm')
#从session里取出验证码
verifycode = request.session['verifycode']
# if yzm == verifycode:
# return HttpResponse('ok')
# else:
# return HttpResponse('no')
response = HttpResponse('no')
if yzm == verifycode:
response = HttpResponse('ok')
return response
- 输入网址:http://127.0.0.1:8000/verify_show/验证如下:
输入正确
随便输入时:
(此文章仅作为个人学习笔记使用,如有错误欢迎指正~)
网友评论