- 模板介绍
1 模板概述
1)作为Web框架,Django提供了模板,可以很便利的动态生HTML
2)模版系统致力于表达外观,而不是程序逻辑。
3)模板的设计实现了业务逻辑(view)与显示内容(template)的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用。
4)模板包含:
-
- HTML的静态部分
- 动态插入内容部分
5)Django模板语言,简写DTL,定义在django.template包中,由startproject命令生成的settings.py定义关于模板的值:
-
- DIRS定义了一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板源文件
- APP_DIRS告诉模板引擎是否应该在每个已安装的应用中查找模板,这种便于发布应用
- 常用方式:在项目的根目录下创建templates目录,设置DIRS值
DIRS=[os.path.join(BASE_DIR,"templates")]
2. 模板处理
Django处理模板分为两个阶段
2.1 第一步骤:加载模板
第一步骤加载:根据给定的标识找到模板然后预处理,通常会将它编译好放在内存中
from django.shortcuts import loader loader.get_template(template_name)#返回一个Template对象
2.2第二步骤:渲染模板
第二步骤渲染:使用Context数据对模板插值并返回生成的字符串
Template对象的render(RequestContext)方法,使用context渲染模板成标准的html代码
context = RequestContext(request, {"data":"hello world"}) content = tem.render(context)#content渲染出来标准的html代码
2.3 加载渲染完整代码:
from django.template import loader, RequestContext from django.http import HttpResponse def index(request): tem = loader.get_template('temtest/index.html')#返回一个Template对象 context = RequestContext(request, {"data":"hello world"}) content = tem.render(context)#content渲染出来标准的html代码 return HttpResponse(content)
return render(request,’index.html’,{
‘data’:’helloworld’
})
3. 快捷函数
1)为了减少加载模板、渲染模板的重复代码,django提供了快捷函数
2)render_to_string("")
3)render(request,'模板',context)
from django.shortcuts import render def index(request): return render(request, 'index.html')
二、定义模板
1. 模板语言(DTL)主要内容
1)变量
2)标签 { % 代码块 % }
3)过滤器
4)注释{# 代码或html #}
2. 变量
1)语法:
{{ variable }}
2)当模版引擎遇到一个变量,将计算这个变量,然后将结果输出
3)变量名必须由字母、数字、下划线(不能以下划线开头)和点组成
4)当模版引擎遇到点("."),会按照下列顺序查询:
-
- 字典查询,例如:foo["bar"] {{foo.bar}}
- 属性或方法查询,例如:foo.bar
- 数字索引查询,例如:foo[bar] {{all_students.0}}
5)如果变量不存在, 模版系统将插入'' (空字符串)
6)在模板中调用方法时不能传递参数
3. 在模板中调用对象的方法和属性
4. 标签
1)语法:{ % tag % }
2)作用
-
- 在输出中创建文本
- 控制循环或逻辑
- 加载外部信息到模板中供以后的变量使用
4.1 for标签
4.1.1 语法
{ %for ... in ...%}
循环逻辑
{{forloop.counter}}
表示当前是第几次循环
{ %empty%}
给出的列表为或列表不存在时,执行此处
{ %endfor%}
4.2 if标签
4.2. 1语法
{ %if ...%}
逻辑
1
{ %elif ...%}
逻辑
2
{ %else%}
逻辑
3
{ %endif%}
4.3 comment标签,多行注释
{ % comment % }
多行注释
{ % endcomment % }
4.4 include:加载模板并以标签内的参数渲染
可以包含另外一个模块过来
{ %include "foo/bar.html" % }
4.5 url:反向解析
4.5.1 语法
语法:'p1'
和
'p2'
是数据
{ % url 'name' 'p1' 'p2' %}?=’get
请求方式
’
4.6 csrf_token:这个标签用于跨站请求伪造保护
{ % csrf_token %}
5. 过滤器
5.1 过滤器语法
1)语法:{ { 变量|过滤器 }}
2)例如{ { name|lower }},表示将变量name的值变为小写输出
3)使用管道符号 (|)来应用过滤器
4)通过使用过滤器来改变变量的计算结果
5.2 过滤器常用形式
1)可以在if标签中使用过滤器结合运算符
if list1|length > 1
2)过滤器能够被“串联”,构成过滤器链
name|lower|upper
3)过滤器可以传递参数,参数使用引号包起来
list|join:", "
引号必须为双引号
4)default:如果一个变量没有被提供,或者值为false或空,则使用默认值,否则使用变量的值
value|default:"
什么也没有
"
5)date:根据给定格式对一个date变量格式化
value|date:'Y-m-d'
6)escape:详见“HTML转义”
5.3 Django 过滤器表
过滤器 | 描述 | 示例 |
upper | 以大写方式输出 | {{ user.name | upper }} |
add | 给value加上一个数值 | {{ user.age | add:”5” }} |
addslashes | 单引号加上转义号 |
|
capfirst | 第一个字母大写 | {{ ‘good’| capfirst }} 返回”Good” |
center | 输出指定长度的字符串,把变量居中 | {{ “abcd”| center:”50” }} |
cut | 删除指定字符串 | {{ “You are not a Englishman” | cut:”not” }} |
date | 格式化日期 |
|
default | 如果值不存在,则使用默认值代替 | {{ value | default:”(N/A)” }} |
default_if_none | 如果值为None, 则使用默认值代替 |
|
dictsort | 按某字段排序,变量必须是一个dictionary | {% for moment in moments | dictsort:”id” %} |
dictsortreversed | 按某字段倒序排序,变量必须是dictionary |
|
divisibleby | 判断是否可以被数字整除 | {{ 224 | divisibleby:“2”}} 返回 True |
escape | 按HTML转义,比如将”<”转换为”<” | A = ‘<a href=>我爱你</a>’ |
filesizeformat | 增加数字的可读性,转换结果为13KB,89MB,3Bytes等 | {{ 1024 | filesizeformat }} 返回 1.0KB |
first | 返回列表的第1个元素,变量必须是一个列表 |
|
floatformat | 转换为指定精度的小数,默认保留1位小数 | {{ 3.1415926 | floatformat:”3” }} 返回 3.142 四舍五入 |
get_digit | 从个位数开始截取指定位置的数字 | {{ 123456 | get_digit:’1’}} |
join | 用指定分隔符连接列表 | {{ [‘abc’,’45’] | join:’*’ }} 返回 abc*45 |
length | 返回列表中元素的个数或字符串长度 |
|
length_is | 检查列表,字符串长度是否符合指定的值 | {{ ‘hello’| length_is:’3’ }} |
linebreaks | 用<p>或<br>标签包裹变量 | {{ “Hi\n\nDavid”|linebreaks }} 返回<p>Hi</p><p>David</p> |
linebreaksbr | 用<br/>标签代替换行符 |
|
linenumbers | 为变量中的每一行加上行号 |
|
ljust | 输出指定长度的字符串,变量左对齐 | {{‘ab’|ljust:5}}返回 ‘ab ’ |
lower | 字符串变小写 |
|
make_list | 将字符串转换为列表 |
|
pluralize | 根据数字确定是否输出英文复数符号 |
|
random | 返回列表的随机一项 |
|
removetags | 删除字符串中指定的HTML标记 | {{value | removetags: “h1 h2”}} |
rjust | 输出指定长度的字符串,变量右对齐 |
|
slice | 切片操作, 返回列表 | {{[3,9,1] | slice:’:2’}} 返回 [3,9] {{ 'asdikfjhihgie' | slice:':5' }} 返回 ‘asdik’ |
slugify | 在字符串中留下减号和下划线,其它符号删除,空格用减号替换 | {{ '5-2=3and5 2=3' | slugify }} 返回 5-23and5-23 |
stringformat | 字符串格式化,语法同python | 1 | stringformat:”i” |
time | 返回日期的时间部分 |
|
timesince | 以“到现在为止过了多长时间”显示时间变量 | 结果可能为 45days, 3 hours |
timeuntil | 以“从现在开始到时间变量”还有多长时间显示时间变量 |
|
title | 每个单词首字母大写 |
|
truncatewords | 将字符串转换为省略表达方式 | {{ 'This is a pen' | truncatewords:2 }}返回 This is ... |
truncatewords_html | 同上,但保留其中的HTML标签 | {{ '<p>This is a pen</p>' | truncatewords:2 }}返回 <p>This is ...</p> |
urlencode | 将字符串中的特殊字符转换为url兼容表达方式 | {{ ‘http://www.aaa.com/foo?a=b&b=c’ | urlencode}} |
urlize | 将变量字符串中的url由纯文本变为链接 |
|
wordcount | 返回变量字符串中的单词数 |
|
yesno | 将布尔变量转换为字符串yes, no 或maybe | {{ True | yesno }} {{ False | yesno }} {{ None | yesno }} 返回 yes no maybe |
6. 注释
6.1 单行注释
选中要注释的单行代码:Ctrl+/
{#...#}
6.2 注释可以包含任何模版代码,有效的或者无效的都可以
选中要注释的单行代码:Ctrl+/
{# { % if foo % }bar{ % else % } #}
6.3 使用comment标签注释模版中的多行内容
{ % comment % }
多行注释
{ % endcomment % }
三、模板继承
1. 模板概述
1.1 模板继承的好处
1)模板继承可以减少页面内容的重复定义,实现页面内容的重用
2)典型应用:网站的头部、尾部是一样的,这些内容可以定义在父模板中,子模板不需要重复定义
3)block标签:在父模板中预留区域,在子模板中填充
4)extends继承:继承,写在模板文件的第一行
1.2 语法说明
1)定义父模板base.html
block_name
模板名字任意
{ %block block_name%}
这里可以定义默认值
如果不定义默认值,则表示空字符串
{ %endblock%}
2)定义子模板index.html
{ % extends "base.html" %}
3)在子模板中使用block填充预留区域
{ %block block_name%}
实际填充内容
{ %endblock%}
说明
- 如果在模版中使用extends标签,它必须是模版中的第一个标签
- 不能在一个模版中定义多个相同名字的block标签
- 子模版不必定义全部父模版中的blocks,如果子模版没有定义block,则使用了父模版中的默认值
- 如果发现在模板中大量的复制内容,那就应该把内容移动到父模板中
- 使用可以获取父模板中block的内容
- 为了更好的可读性,可以给endblock标签一个名字
{ % block block_name %}
区域内容
{ % endblock block_name %}
- HTML转义
1. HTML自动转义案例
Django对字符串进行自动HTML转义,如在模板中输出如下值:
-
- 视图代码和url配置
视图代码
#html自动转义案例 def htmlTest(request): context = {'data': '<h1>hello</h1>'} return render(request, 'booktest/html_test.html',context )
Url配置
url(r'^htmlTest/$',views.htmlTest,name='htmlTest'),
1.2 模板代码
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>HTML转义</title> </head> <body> <hr> {{ data }} <hr> </body> </html>
1.3 运行显示效果如下图
2. 会被自动转义的字符
2.1 html转义的意义和自动转义的字符
html转义,就是将包含的html标签输出,而不被解释执行,原因是当显示用户提交字符串时,可能包含一些攻击性的代码,如js脚本
2.2 Django会将如下字符自动转义
<
会转换为
<
>
会转换为
>
' (
单引号
)
会转换为
'
" (
双引号
)
会转换为
"
&
会转换为
&
当显示不被信任的变量时使用escape过滤器,一般省略,因为Django自动转义
{{t1|escape}}
3. 关闭转义两种方式
3.1 对于变量使用safe过滤器
{{ data|safe }}
案例
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>HTML转义</title> </head> <body> <hr> {{ data }} <hr> 对于变量使用safe过滤器关闭html转义:<br/> {{ data|safe}} </body> </html>
运行效果:
3.2 对于代码块使用autoescape标签
{ % autoescape off %}
{{ body }}
{ % endautoescape %}
1)标签autoescape接受on或者off参数
2)自动转义标签在base模板中关闭,在child模板中也是关闭的
案例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>HTML转义</title> </head> <body> <hr> {{ data }} <hr> 对于变量使用safe过滤器关闭html转义:<br/> {{ data|safe}} <hr/> 使用autoescape标签关闭转义:<br/> {% autoescape off %} {{ data }} {% endautoescape %} </body> </html>
4. 手动转义
4.1 下面没有转义
{ { data|default:"<b>hello</b>" }}
4.2 应写为下面方式手动转义
{ { data|default:"<b>hello</b>" }}
案例
<hr/> 下面的代码我们希望原始输出:<br/> {{ xixi|default:"<h1>hello</h1>" }} <br> 解决办法:手动转义,让其原始输出: <br/> <h1>hello</h1> </body> </html>
- Csrf
1. Csrf(跨站请求伪造)简介
全称Cross Site Request Forgery,跨站请求伪造。
跨站攻击:某些恶意网站上包含链接、表单按钮或者JavaScript,它们会利用登录过的用户在浏览器中的认证信息试图在你的网站上完成某些操作,这就是跨站攻击。
1.1 演示csrf如下
1.1.1 创建视图csrf1用于展示表单,csrf2用于接收post请求
def csrf1(request): return render(request,'booktest/csrf1.html') def csrf2(request): uname=request.POST['uname'] return render(request,'booktest/csrf2.html',{'uname':uname})
1.1.2 配置url
url(r'^csrf1/$',views.csrf1,name='csrf1'), url(r'^csrf2/$', views.csrf2, name='csrf2'),
1.1.2 创建模板
1)创建模板csrf1.html用于展示表单
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>csrf1</title> </head> <body> <form method="post" action="/booktest/csrf2/"> 请输入账号:<input type="text" name="uname"> <br> <input type="submit" value="提交"> </form> </body> </html>
2)创建模板csrf2用于展示接收的结果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> {{ uname }} </body> </html>
1.1.3 在浏览器中访问,查看效果,报错如下:
指定ip和端口开发临时服务器:
输入账号提交代码
1.1.4 注释掉CsrfViewMiddleware中间件,演示案例
1)将settings.py中的中间件代码'django.middleware.csrf.CsrfViewMiddleware'注释
MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', # 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', )
再次访问,不管是在window和linux上都可以正常访问:
- 查看csrf1的源代码,复制,在自己的网站内建一个html文件,粘贴源码,访问查看效果
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>csrf1</title> </head> <body> <form method="post" action="http://192.168.31.114:8000/booktest/csrf2/"> 请输入账号:<input type="text" name="uname"> <br> <input type="submit" value="提交"> </form> </body> </html>
代码展示如下
2. 防csrf的使用
在django的模板中,提供了防止跨站攻击的方法,使用步骤如下:
2.1 开启默认的CsrfViewMiddleware中间件
在settings.py中启用'django.middleware.csrf.CsrfViewMiddleware'中间件,此项在创建项目时,默认被启用
MIDDLEWARE_CLASSES = ( 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.auth.middleware.SessionAuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'django.middleware.security.SecurityMiddleware', )
2.2 在csrf1.html中添加标签
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>csrf1</title> </head> <body> <form method="post" action="/booktest/csrf2/"> {% csrf_token %} 请输入账号:<input type="text" name="uname"> <br> <input type="submit" value="提交"> </form> </body> </html>
2.3 测试刚才的两个请求,发现跨站的请求被拒绝了,效果如下图
3. 取消保护
3.1 使用装饰器csrf_exempt
如果某些视图不需要保护,可以使用装饰器csrf_exempt,模板中也不需要写标签,修改csrf2的视图如下
from django.views.decorators.csrf import csrf_exempt @csrf_exempt def csrf2(request): uname=request.POST['uname'] return render(request,'booktest/csrf2.html',{'uname':uname})
3.2 运行上面的两个请求,发现都可以请求
4. 保护原理
4.1 加入标签后,可以查看源代码,发现多了如下代码
<input type='hidden' name='csrfmiddlewaretoken' value='7Lp0vtQgqeblwInOd8MnBoUdSUSluTlX' />
7Lp0vtQgqeblwInOd8MnBoUdSUSluTlX
- 在浏览器的调试工具中,通过network标签可以查看cookie信息
4.2 本站中自动添加了cookie信息,如下图
7Lp0vtQgqeblwInOd8MnBoUdSUSluTlX
4.3 查看跨站的信息,并没有cookie信息,即使加入上面的隐藏域代码,发现又可以访问了
在a.html里面
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>csrf1</title> </head> <body> <form method="post" action="http://192.168.31.114:8000/booktest/csrf2/"> <input type='hidden' name='csrfmiddlewaretoken' value='7Lp0vtQgqeblwInOd8MnBoUdSUSluTlX' /> 请输入账号:<input type="text" name="uname"> <br> <input type="submit" value="提交"> </form> </body> </html>
有可以访问了
4.4 结论:django的csrf不是完全的安全
当提交请求时,中间件'django.middleware.csrf.CsrfViewMiddleware'会对提交的cookie及隐藏域的内容进行验证,如果失败则返回403错误
六、验证码
https://blog.csdn.net/daqinjun/article/details/72123099?utm_source=itdadao&utm_medium=referral
在用户注册、登录页面,为了防止暴力请求,可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻一些服务器的压力
使用验证码也是一种有效的防止crsf的方法
- 验证码效果如下图:
1. 验证码视图
- 新建viewsUtil.py,定义函数verifycode
- 此段代码用到了PIL中的Image、ImageDraw、ImageFont模块,需要先安装Pillow(3.4.1)包,详细文档参考http://pillow.readthedocs.io/en/3.4.x/
- http://pillow.readthedocs.io/en/5.1.x/
安装命令:pip3 install pillow
- Image表示画布对象
- ImageDraw表示画笔对象
- ImageFont表示字体对象,ubuntu的字体路径为“/usr/share/fonts/truetype/freefont”
安装命令:pip3 install pillow
- 用代码生成验证码并且在服务器中验证
- 原理版本
2.1.1 代码
/booktest/views.py里面
from PIL import Image,ImageDraw,ImageFont from random import randrange import io #生成验证码图片 def verityCode(request): #创建图片背景 red = randrange(50,100) green = randrange(50,100) blue = 0 bgColor = (red,green,blue) #规定宽和高 width = 100 height = 25 #定义画布 image = Image.new("RGB",(width, height),bgColor) #创建画笔 draw = ImageDraw.Draw(image) #绘制文本图片 # 构造字体对象 font = ImageFont.truetype('FreeMono.ttf', 24) text = "ABCD" draw.text((0,0),text,font=font) #保存图片以流的方式在内存中 buf = io.BytesIO() image.save(buf,format="png") # 将内存流中的内容输出到客户端 return HttpResponse(buf.getvalue(), 'image/png')
配置url
url(r'^verityCode/$', views.verityCode, name='verityCode'),
请求看效果:
2.1.2 做成随机的
from PIL import Image,ImageDraw,ImageFont from random import randrange import io #生成验证码图片 def verityCode(request): #创建图片背景 red = randrange(50,100) green = randrange(50,100) blue = 0 bgColor = (red,green,blue) #规定宽和高 width = 100 height = 25 #定义画布 image = Image.new("RGB",(width, height),bgColor) #创建画笔 draw = ImageDraw.Draw(image) #绘制文本图片 # 构造字体对象 font = ImageFont.truetype('FreeMono.ttf', 24) #构造随机生成验证码 text = "123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" for i in range(4): draw.text((i*25,0),text[randrange(0,len(text))],font=font) # draw.text((0, 0), text, font=font) #保存图片以流的方式在内存中 buf = io.BytesIO() image.save(buf,format="png") # 将内存流中的内容输出到客户端 return HttpResponse(buf.getvalue(), 'image/png')
运行效果:
七、表的查找和过滤综合
返回查询集:
-
- all()
- filter()条件满足的
- exclude()条件相反的
- order_by()按照上面排序的集合
- values():一个对象构成一个字典,然后构成一个列表返回,相当于json数据,很方便实用。
- 限制查询集:返回的查询集支持切片操作,但是不支持负索引
返回单个值:
-
- get():返回单个满足条件的对象
- 如果未找到会引发"模型类.DoesNotExist"异常
- count():返回当前查询的总条数
- first():返回第一个对象
- last():返回最后一个对象
- exists():判断查询集中是否有数据,如果有则返回True,没有返回False
- get():返回单个满足条件的对象
filter条件过滤:
1、条件运算符
判断等于__exact 等价于= 完全等于
2、模糊查询contains
3、__startswith、__endswith 以什么开头和结束
4、在前面加个i表示不区分大小写,如iexact、icontains、istartswith、 iendswith
5、__isnull 是否为null __isnull = True 或者 __isnull = False
6、__in是否包含在范围内 pk__in = [1,2,3,4,5] 或者 id__in=[1,2,3,4,5]
7、gt、gte、lt、lte:大于、大于等于、小于、小于等于 id__gt=3
8、year、month、day、week_day、hour、minute、second:对日期间类型的 属性进行运算 add_time__year__gt=2016
F和Q对象
1、F对象的作用
1)可以使用模型的字段A与字段B进行比较,如果A写在了等号的左边,则B出现在等号的右边,需要通过F对象构造。
StudentInfo.student_manager.filter(age__gt=F('id'))
2)支持F对象对字段进行运算操作
StudentInfo.student_manager.filter(age__gt=F('id')*3)
StudentInfo.student_manager.filter(age__gt=F('id')+3)
2、Q对象的作用
与或非的操作
与操作:StudentInfo.student_manager.filter(Q(name='zhaoliying')&Q(age=13))
或操作:StudentInfo.student_manager.filter(Q(name='zhaoliying')|Q(age=18))
反操作:StudentInfo.student_manager.filter(~Q(name='zhaoliying'))
八、自定义模型管理器
1、我们可以定制自己的管理器重写all方法,返回自己需要的查询集(可以为一个模型定义多个管理器,多个管理器可以共存)
2、我们可以在自定的管理器当中增加创建对象的方法对数据表进行增加操作