04 Django 模板

  • 基本概念
    • 作为Web框架,Django提供了模板,用于编写html代码,还可以嵌入模板代码更快更方便的完成页面开发,再通过在视图中渲染模板,将生成最终的html字符串返回给客户端浏览器
    • 模版致力于表达外观,而不是程序逻辑。模板的设计实现了业务逻辑view与显示内容template的分离,一个视图可以使用任意一个模板,一个模板可以供多个视图使用
    • 组成
      • 静态部分,包含html、css、js
      • 动态部分,就是模板语言
  • 模板文件
    • 使用
    • 模板文件的加载顺序
      • 04 Django 模板
      • 首先去配置的模板目录下面去找模板文件
      • 去INSTALLED_APPS下面的每个应用的templates去找模板文件,前提是应用中必须有templates文件夹
  • 模板语言
    • 模板语言简称为 DTL(Django Template Language)
    • 模板变量
      • 模板变量名是由数字,字母,下划线和点组成的,不能以下划线开头
      • 使用模板变量

{{模板变量名}}

  • 模板变量的解析
    • 解析顺序
      • {{ book.btitle }}
        • 首先把 book 当成一个字典,把 btitle 当成键名,进行取值 book['btitle']
        • 把 book 当成一个对象,把 btitle 当成属性,进行取值 book.btitle
        • 把 book 当成一个对象,把 btitle 当成对象的方法,进行取值 book.btitle
      • {{ book.0 }}
        • 首先把book当成一个字典,把0当成键名,进行取值book[0]
        • 把book当成一个列表,把0当成下标,进行取值book[0]
    • 如果解析失败,则产生内容时用空字符串填充模板变量。
    • 使用模板变量时,. 前面的可能是一个字典,可能是一个对象,还可能是一个列表
  • 模板标签
    • 使用方法

{% 代码段 %}

  • for 循环

{% for x in 列表 %}

# 列表不为空时执行

{% empty %}

# 列表为空时执行

{% endfor %}

  • 可以通过 {{ forloop.counter }} 得到 for 循环遍历到了第几次
  • 条件语句

{% if 条件 %}

{% elif 条件 %}

{% else %}

{% endif %}

  • 关系比较运算符
    • > < >= <= == !=
    • 进行比较运算时,比较操作符两边必须有空格
  • 逻辑运算
    • not and or

模板变量|过滤器:参数

  • 其中 : 后不能有空格
  • 常用过滤器
    • date
      • 改变日期的显示格式
    • length
      • 求长度。字符串,列表.
    • default
      • 设置模板变量的默认值
  • 自定义过滤器
    • 至少有一个参数,最多只能有两个参数
    • 示例:一个参数
      • 在应用中创建templatetags目录,当前示例为"booktest/templatetags"(文件名不可更改),创建__init__文件,内容为空
        • 04 Django 模板
      • 在"booktest/templatetags"目录下创建 filters.py (文件名可自定义)文件,代码如下:

#导入Library类

from django.template import Library

   

#创建一个Library类对象

register=Library()

   

#使用装饰器进行注册

@register.filter

#定义求余函数mod,将value对2求余

def iseven(value):

return value%2 == 0

  

  • 在 templates/booktest/temp_filter.html 中,使用自定义过滤器
    • 首先使用load标签引入模块

{%load filters%}

  • 在遍历时根据编号判断奇偶,调用格式如下

显示 id 为偶数的图书

<ul>

{% for book in books %}

{% if book.id|iseven %}

<li class="red">{{ book.id }}--{{book.btitle}}--

{{ book.bpub_date|date:"Y 年 m 月 d 日" }}</li>

{% endif %}

{% endfor %}

</ul>

  • 示例:两个参数,其中接收一个参数
    • 在 filters.py 中添加如下函数

@register.filter

def mod(num, dividend):

"""判断 num 是否能被 dividend 整除"""

return num % dividend == 0

  • 在使用load标签引入模块后,调用格式如下:

显示 id 能被 3 整除的图书

<ul>

{% for book in books %}

{% if book.id|mod:3 %}

<li class="red">{{ book.id }}--{{book.btitle}}--

{{ book.bpub_date|date:"Y 年 m 月 d 日" }}</li>

{% endif %}

{% endfor %}

</ul>

  • 模板注释
    • 单行注释

{# 注释内容 #}

  • 多行注释

{% comment %}

注释内容

{% endcomment %}

  • 模板继承
    • 示意图
      • 04 Django 模板
    • 在父模板中可以定义块

{% block 块名 %}

块中间可以写内容,也可以不写

{% endblock 块名%}

  • 子模板的继承格式

{% extends 父模板文件路径%} 

  • 子模块对块中的内容进行操作

{% block 块名 %}

{{ block.super}} #获取父模板中块的默认内容

重写的内容

{% endblock 块名%}

  • html 转义
    • 在模板上下文中的 html 标记默认是会被转义的
      • 小于号< 转换为&lt;
      • 大于号> 转换为&gt;
      • 单引号' 转换为&#39;
      • 双引号" 转换为 &quot;
      • 与符号& 转换为 &amp;
    • 关闭上下文字符串的方法

{{ 模板变量|safe}}

  • 使用 autoesacpe 标签

{% autoescape off %}

模板语言代码

{% endautoescape %}

  • 模板硬编码中的字符串默认不会经过转义

模板硬编码不转义:{{data|default:'<b>hello</b>'}}

<br />

模板硬编码手动转义:{{data|default:"&lt;b&gt;123&lt;/b&gt;"}}

  • csrf 攻击
    • 基本概念
      • CSRF全拼为Cross Site Request Forgery,译为跨站请求伪造
      • 指攻击者盗用了你的身份,以你的名义发送恶意请求
      • CSRF能够做的事情包括:以你名义发送邮件,发消息,盗取你的账号,甚至于购买商品,虚拟货币转账......
      • 造成的问题包括:个人隐私泄露以及财产安全
      • 示意图
        • 04 Django 模板
    • 防止方法
      • 首先是重要的信息传递都采用 POST 方式而不是 GET 方式
      • POST 方式避免 csrf 攻击需要采取特殊的措施
      • django 中的防止方法
        • 在 setting.py 中启用 csrf 中间件
        • 在 form 表单中使用标签 csrf_token

<!DOCTYPE html>

<html lang="en">

<head>

<meta charset="UTF-8">

<title>发帖页</title>

</head>

<body>

<form method="post" action="/post_action/">

{% csrf_token %}

标题:<input type="text" name="title"/><br/>

内容:<textarea name="content"></textarea>

<input type="submit" value="发帖"/>

</form>

</body>

</html>

  • django 中的保护原理
    • 加入标签后,可以查看网页的源代码,会发现多了一个隐藏域
      • 04 Django 模板
    • 查看 cookie 信息
      • 04 Django 模板
    • 当启用中间件并加入标签csrf_token后,会向客户端浏览器中写入一条 Cookie 信息,这条信息的值与隐藏域 input 元素的 value 属性是一致的,提交到服务器后会先由 csrf 中间件进行验证,如果对比失败则返回 403 页面,而不会进行后续的处理
  • 验证码
    • 在用户注册、登录页面,为了防止暴力请求,可以加入验证码功能,如果验证码错误,则不需要继续处理,可以减轻业务服务器、数据库服务器的压力
    • 实现验证码
      • 在当前环境中安装包 Pillow 3.4.1

pip install Pillow==3.4.1

  • PIL模块API,示例中使用了 Image、ImageDraw、ImageFont对象及方法
  • 在booktest/views.py文件中,创建视图verify_code
    • 随机生成字符串后存入session中,用于后续判断
    • 视图返回 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),

  • 浏览器效果图
    • 04 Django 模板
    • 刷新后验证码会发生变化
  • 调用验证码
    • 在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>

  • 浏览效果
    • 04 Django 模板
  • 验证
    • 在 booktest/views.py 文件中,创建视图 verify_yz

def verify_yz(request):

yzm=request.POST.get('yzm')

verifycode=request.session['verifycode']

response=HttpResponse('no')

if yzm==verifycode:

response=HttpResponse('ok')

return response

  • 打开booktest/urls.py文件,配置url

url(r'^verify_yz/$', views.verify_yz),

  • 浏览器中的效果
    • 04 Django 模板

         

    • 04 Django 模板
  • url 反向解析
    • 当某一个url配置的地址发生变化时,页面上使用反向解析生成地址的位置不需要发生变化
    • 反向解析应用在两个地方:模板中的超链接,视图中的重定向
    • 要实现反向解析功能,需要如下步骤:
      • 在 test4/urls.py中 为 include 定义 namespace 属性

url(r'^',include('booktest.urls',namespace='booktest')),

  • 在booktest/urls.py中为url定义name属性,并修改为fan2

url(r'^fan2/$', views.fan2,name='fan2'),

  • django 2.0 版本需要指定 app_name

app_name = 'cart'

  • 在模板中使用url标签做超链接,此处为 templates/booktest/fan1.html 文件

<html>

<head>

<title>反向解析</title>

</head>

<body>

普通链接:<a href="/fan2/">fan2</a>

<br>

反向解析:<a href="{%url 'booktest:fan2'%}">fan2</a>

</body>

</html>

  • 浏览器中查看源代码
    • 04 Django 模板
  • 在 booktest/urls.py 中,将 fan2 修改为 fan_show

url(r'^fan_show/$', views.fan2,name='fan2'), 

  • 回到浏览器中,刷新,查看源文件如下图,可看出两个链接地址不一样
    • 04 Django 模板
  • 应用于视图重定向中

from django.shortcuts import redirect

from django.core.urlresolvers import reverse

   

return redirect(reverse('booktest:fan2'))

  • 相关总结
    • 在模板中
      • 无参数

{% url 'namespace名字:name' %} 例如{% url 'booktest:fan2'%} 

  • 位置参数

{% url 'namespace名字:name' 参数 %} 例如{% url 'booktest:fan2' 1 2%}

  • 关键字参数

{% url 'namespace名字:name' 关键字参数 %} 例如{% url 'booktest:fan2' id=1 name='lijunjie'%} 

  • 在视图重定向中
    • 首先导入 reverse 模块

from django.core.urlresolvers import reverse 

  • 无参数

reverse('namespace名字:name名字') 

  • 位置参数

reverse('namespace名字:name名字', args = 位置参数元组) 

  • 关键字参数

reverse('namespace名字:name名字', kwargs=字典) 

 

上一篇:Mockito初探(二)——常用功能


下一篇:php – 成功付款后验证新用户的最佳方式是什么?