美文网首页
web应用框架——Django模板+验证码功能

web应用框架——Django模板+验证码功能

作者: 思君_4cd3 | 来源:发表于2020-04-27 15:48 被阅读0次

一.模板

作为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>

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>

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

(此文章仅作为个人学习笔记使用,如有错误欢迎指正~)

相关文章

网友评论

      本文标题:web应用框架——Django模板+验证码功能

      本文链接:https://www.haomeiwen.com/subject/bifiihtx.html