1.模板介绍:模版系统致力于表达外观,而不是程序逻辑 视图:模板=1:n
模板包含:HTML的静态部分 动态插入内容部分
Django模板语言,简写DTL,定义在django.template包中,由startproject命令生成的settings.py定义关于模板的值:
DIRS定义了一个目录列表,模板引擎按列表顺序搜索这些目录以查找模板源文件
APP_DIRS告诉模板引擎是否应该在每个已安装的应用中查找模板
常用方式:在项目的根目录下创建templates目录,设置DIRS值
DIRS=[os.path.join(BASE_DIR,"templates")]
2.模板处理
Django处理模板分为两个阶段
Step1 加载:根据给定的标识找到模板然后预处理,通常会将它编译好放在内存中
loader.get_template(template_name),返回一个Template对象
Step2 渲染:使用Context数据对模板插值并返回生成的字符串
Template对象的render(RequestContext)方法,使用context渲染模板
加载渲染完整代码:
from django.template import loader, RequestContext
from django.http import HttpResponse
def index(request):
tem = loader.get_template('temtest/index.html')
context = RequestContext(request, {})
return HttpResponse(tem.render(context))
快捷函数:为了减少加载模板、渲染模板的重复代码,django提供了快捷函数
render_to_string("")
render(request,'模板',context)
from django.shortcuts import render
def index(request):
return render(request, 'temtest/index.html')
CSRF 背景与介绍
CSRF(Cross Site Request Forgery, 跨站域请求伪造)是一种网络的攻击方式,它在 2007 年曾被列为互联网 20 大安全隐患之一。其他安全隐患,比如 SQL 脚本注入,跨站域脚本攻击等在近年来已经逐渐为众人熟知,很多网站也都针对他们进行了防御。然而,对于大多数人来说,CSRF 却依然是一个陌生的概念。即便是大名鼎鼎的 Gmail, 在 2007 年底也存在着 CSRF 漏洞,从而被黑客攻击而使 Gmail 的用户造成巨大的损失。
CSRF 攻击实例
CSRF 攻击可以在受害者毫不知情的情况下以受害者名义伪造请求发送给受攻击站点,从而在并未授权的情况下执行在权限保护之下的操作。比如说,受害者 Bob 在银行有一笔存款,通过对银行的网站发送请求 可以使 Bob 把 1000000 的存款转到 bob2 的账号下。通常情况下,该请求发送到网站后,服务器会先验证该请求是否来自一个合法的 session,并且该 session 的用户 Bob 已经成功登陆。黑客 Mallory 自己在该银行也有账户,他知道上文中的 URL 可以把钱进行转帐操作。Mallory 可以自己发送一个请求给银行:http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory。但是这个请求来自 Mallory 而非 Bob,他不能通过安全认证,因此该请求不会起作用。这时,Mallory 想到使用 CSRF 的攻击方式,他先自己做一个网站,在网站中放入如下代码: src=”http://bank.example/withdraw?account=bob&amount=1000000&for=Mallory ”,并且通过广告等诱使 Bob 来访问他的网站。当 Bob 访问该网站时,上述 url 就会从 Bob 的浏览器发向银行,而这个请求会附带 Bob 浏览器中的 cookie 一起发向银行服务器。大多数情况下,该请求会失败,因为他要求 Bob 的认证信息。但是,如果 Bob 当时恰巧刚访问他的银行后不久,他的浏览器与银行网站之间的 session 尚未过期,浏览器的 cookie 之中含有 Bob 的认证信息。这时,悲剧发生了,这个 url 请求就会得到响应,钱将从 Bob 的账号转移到 Mallory 的账号,而 Bob 当时毫不知情。等以后 Bob 发现账户钱少了,即使他去银行查询日志,他也只能发现确实有一个来自于他本人的合法请求转移了资金,没有任何被攻击的痕迹。而 Mallory 则可以拿到钱后逍遥法外。
1.定义模板:模板获取后端的数据,来源于context进行传递
模板语言包括
变量 标签 { % 代码块 % } 过滤器 注释{# 代码或html #}
变量 {
{ variable }}:当模版引擎遇到一个变量,将计算这个变量,然后将结果输出当模版引擎遇到点("."),会按照下列顺序查询:字典->属性方法->数组
1.字典查询,例如:foo["bar"]
2.属性或方法查询,例如:foo.bar
3.数字索引查询,例如:foo[bar]
如果变量不存在, 模版系统将插入'' (空字符串)
在模板中调用方法时不能传递参数
在模板中调用对象的方法
在models.py中定义类HeroInfo
from django.db import models
class HeroInfo(models.Model):
...
def showName(self):
return self.hname
在views.py中传递HeroInfo对象
from django.shortcuts import render
from models import *
def index(request):
hero = HeroInfo(hname='abc')
context = {'hero': hero}
return render(request, 'temtest/detail.html', context)
在模板detail.html中调用
{
{hero.showName}}标签
语法:{ % tag % }
for标签
{ %for ... in ...%}
循环逻辑
{
{forloop.counter}}表示当前是第几次循环{ %empty%}
给出的列表为或列表不存在时,执行此处
{ %endfor%}
url:反向解析
{ % url 'name' p1 p2 %}
csrf_token:这个标签用于跨站请求伪造保护
{ % csrf_token %}
布尔标签:and、or,and比or的优先级高
block、extends:详见“模板继承”
autoescape:详见“HTML转义”
过滤器
语法:{ { 变量|过滤器 }},例如{ { name|lower }},表示将变量name的值变为小写输出
使用管道符号 (|)来应用过滤器
通过使用过滤器来改变变量的计算结果
可以在if标签中使用过滤器结合运算符
if list1|length > 1
过滤器能够被“串联”,构成过滤器链
name|lower|upper
过滤器可以传递参数,参数使用引号包起来
list|join:", "
default:如果一个变量没有被提供,或者值为false或空,则使用默认值,否则使用变量的值
value|default:"什么也没有"
date:根据给定格式对一个date变量格式化
value|date:'Y-m-d'
escape:详见“HTML转义”
2.模板继承:模板继承可以减少页面内容的重复定义,实现页面内容的重用
典型应用:网站的头部、尾部是一样的
block标签:在父模板中预留区域,在子模板中填充,如果在模版中使用extends标签,它必须是模版中的第一个标签
extends继承:继承,写在模板文件的第一行
定义父模板base.html
{ %block block_name%}
这里可以定义默认值
如果不定义默认值,则表示空字符串
{ %endblock%}
定义子模板index.html
{ % extends "base.html" %}
在子模板中使用block填充预留区域
{ %block block_name%}
实际填充内容
{ %endblock%}
说明
1.子模版不必定义全部父模版中的blocks,如果子模版没有定义block,则使用了父模版中的默认值
2.如果发现在模板中大量的复制内容,那就应该把内容移动到父模板中
3.使用可以获取父模板中block的内容,为了更好的可读性,可以给endblock标签一个名字
{ % block block_name %}
区域内容
{ % endblock block_name %}
三层继承结构
三层继承结构使代码得到最大程度的复用,并且使得添加内容更加简单
1.创建根级模板
名称为“base.html”
存放整个站点共用的内容
<!DOCTYPE html>
<html>
<head>
<title>{%block title%}{%endblock%} 水果超市</title>
</head>
<body>
top--{
{logo}}<hr/>
{%block left%}{%endblock%}
{%block content%}{%endblock%}
<hr/>
bottom
</body>
</html>
2.创建分支模版
继承自base.html
名为“base_*.html”
定义特定分支共用的内容
定义base_goods.html
{%extends 'temtest/base.html'%}
{%block title%}商品{%endblock%}
{%block left%}
<h1>goods left</h1>
{%endblock%}
定义base_user.html
{%extends 'temtest/base.html'%}
{%block title%}用户中心{%endblock%}
{%block left%}
<font color='blue'>user left</font>
{%endblock%}
定义index.html,继承自base.html,不需要写left块
{%extends 'temtest/base.html'%}
{%block content%}
首页内容
{%endblock content%}
3.为具体页面创建模板,继承自分支模板
定义商品列表页goodslist.html
{%extends 'temtest/base_goods.html'%}
{%block content%}
商品正文列表
{%endblock content%}
定义用户密码页userpwd.html
{%extends 'temtest/base_user.html'%}
{%block content%}
用户密码修改
{%endblock content%}
4.视图调用具体页面,并传递模板中需要的数据
首页视图index
logo='welcome to itcast'
def index(request):
return render(request, 'temtest/index.html', {'logo': logo})
商品列表视图goodslist
def goodslist(request):
return render(request, 'temtest/goodslist.html', {'logo': logo})
用户密码视图userpwd
def userpwd(request):
return render(request, 'temtest/userpwd.html', {'logo': logo})
5.配置url
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^$', views.index, name='index'),
url(r'^list/$', views.goodslist, name='list'),
url(r'^pwd/$', views.userpwd, name='pwd'),]
3.HTML转义:就是将代码对应转换成HTML对应的标签
Django对字符串进行自动HTML转义
会被自动转义的字符
html转义,就是将包含的html标签输出,而不被解释执行,原因是当显示用户提交字符串时,可能包含一些攻击性的代码,如js脚本
Django会将如下字符自动转义:
< 会转换为<
> 会转换为>
' (单引号) 会转换为'
" (双引号)会转换为 "
& 会转换为 &
当显示不被信任的变量时使用escape过滤器,一般省略,因为Django自动转义
{
{t1|escape}}关闭转义
对于变量使用safe过滤器
{
{ data|safe }}对于代码块使用autoescape标签
{ % autoescape off %}
{
{ body }}{ % endautoescape %}
标签autoescape接受on或者off参数
自动转义标签在base模板中关闭,在child模板中也是关闭的字符串字面值
手动转义{ { data|default:"<b>123</b>" }}
应写为{ { data|default:"<b>123</b>" }}
4.csrf:全称Cross Site Request Forgery,跨站请求伪造
某些恶意网站上包含链接、表单按钮或者JavaScript,它们会利用登录过的用户在浏览器中的认证信息试图在你的网站上完成某些操作,这就是跨站攻击
将settings.py中的中间件代码'django.middleware.csrf.CsrfViewMiddleware'注释
在django的模板中,提供了防止跨站攻击的方法,使用步骤如下:
step1:在settings.py中启用'django.middleware.csrf.CsrfViewMiddleware'中间件,此项在创建项目时,默认被启用
step2:在csrf1.html中添加标签
<form>
{% csrf_token %}
...
</form>
step3:测试刚才的两个请求,发现跨站的请求被拒绝了,效果如下图
csrf2
取消保护
如果某些视图不需要保护,可以使用装饰器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})
运行上面的两个请求,发现都可以请求
保护原理
加入标签后,可以查看源代码,发现多了如下代码
<input type='hidden' name='csrfmiddlewaretoken' value='nGjAB3Md9ZSb4NmG1sXDolPmh3bR2g59' />
当提交请求时,中间件'django.middleware.csrf.CsrfViewMiddleware'会对提交的cookie及隐藏域的内容进行验证,如果失败则返回403错误