django高级拓展(7)

更新源

pip install --upgrade pip

@验证码

作用:

  • 在用户登录,注册以及一些敏感操作的时候,我们为了防止服务器被暴力请求,或爬虫爬取,我们可以使用验证码进行过滤,减轻服务器的压力。
  • 防止
    @代码块
def main(request):
    #引入绘图模块
    import os
    from PIL import Image, ImageDraw, ImageFont
    from django.http import HttpResponse
    from django.shortcuts import render

    #引入随机函数模块
    import random
    #定义变量,用于画面的背景色,宽,高
    bgcolor = (random.randrange(20,100),random.randrange(20,100),random.randrange(20,100))
    width = 100
    height = 50
    #创建画面对象
    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)
    # 定义验证码的备选值
    str='1234567890QWERTYUIOPASDFGHJKLZXCVBNMqwertyuiopasdfghjklzxcvbnm'
    #随机选取4个值作为验证码
    rand_str = ''
    for i in range(0,4):
        rand_str += str[random.randrange(0,len(str))]
    #构造字体对象

    font = ImageFont.truetype(r'/home/myroot/PycharmProjects/verifycode/stat/fonts/SourceHanSerifCN-ExtraLight.otf',40)
    fontcolor1 = (255,random.randrange(0,255),random.randrange(0,255))
    fontcolor2 = (255,random.randrange(0,255),random.randrange(0,255))
    fontcolor3 = (255,random.randrange(0,255),random.randrange(0,255))
    fontcolor4 = (255,random.randrange(0,255),random.randrange(0,255))
    #绘制4个字
    draw.text((5,2),rand_str[0],font = font,fill=fontcolor1)
    draw.text((25,2),rand_str[1],font = font,fill=fontcolor2)
    draw.text((50,2),rand_str[2],font = font,fill=fontcolor3)
    draw.text((75,2),rand_str[3],font = font,fill=fontcolor4)
    #释放画笔
    del draw
    #存入session,用于做进一步验证
    #request.session['verifycode'] = rand_str
    #内存文件操作
    import io
    buf = io.BytesIO()
    #将突破保存在内存中,文件类型为png
    im.save(buf,'png')
    #将内存中的图片数据返回给客户端,MIM类型为图片png
    return HttpResponse(buf.getvalue(),'image/png')

@验证码的使用
先创建一个路由指向验证码,填写表单的是时候加上验证码图片

<img src =‘指向验证码的路由’>

如果需要实现验证效果的把验证码内的

#request.session['verifycode'] = rand_str

这一行解开注释,在把提交栏内的值code1 = request.POST.get(‘提交栏的name’)和验证码的code2=request.session(‘verifycode’)比较。

@中间件
概念:一个轻量级,底层的插件,可以介入Django的请求和响应
本质:一个python类
方法:

__init__:不需要传参数,服务器响应第一个请求的时候自动调用,用于确定是否启用该中间件

process_request(self,request):在执行视图之前被调用(分配url匹配视图之前),每个请求都会调用,返回None或者HttpResponse对象,作用是判断否有异常请求,并做出处理

process_view(self,request,view_func,view_args,view_kwargs):调用视图之前执行,每个请求都会调用,返回None或者HttpResponse对象

process_template_response(self,request,response):在视图刚好执行完后调用,每个请求都会调用,返回None或者HttpResponse对象

process_response(self,request,response):所有响应返回浏览器之前调用,每个请求都会调用,返回None或者HttpResponse对象

process_exception(self,request,exception):当视图抛出异常时会调用,返回HttpResponse对象

@自定义中间件
就是面向切面编程

切点(钩子)
切点允许我们动态的在原有逻辑中插入一部分代码
在不修改原有代码的情况下,动态注入一部分代码
默认情况,不中断传播,切点会自动愈合(自动执行原有逻辑)
如果我们执行了中断操作(returnraise),没接上,会直接到程序结尾

django的中间件

#没有参数,服务器响应第一个请求的时候自动调用,用户确定是否启用该中间件
__init__

#在执行视图前被调用,每个请求上都会调用,不返回或返回HttpResponse对象
process_request(self,request)

#调用视图之前执行,每个请求都会调用,不返回或返回HttpResponse对象
process_view(self,request,view_func,view_args,view_kwargs)

#在视图刚好执行完后进行调用,每个请求都会调用,不返回或返回HttpResponse对象
process_template_response(self,request,response)

#所有响应返回浏览器之前调用,每个请求都会调用,不返回或返回HttpResponse对象
process_response(self,request,response)

#当视图抛出异常时调用,不返回或返回HttpResponse对象
process_exception(self,request,exception)

自定义的中间件

  • 用途
    统计,黑名单,白名单,反爬,界面友好化(捕获异常)
    在工程目录下新建一个middleware文件,再创建一个应用的子文件myApp文件下再新建一个py文件
    导入指定的库
class LearnAOP(MiddlewareMixin):
    def process_request(self,request):
        print('request的路径',request.GET.path)
from django.utils.deprecation import MiddlewareMixin
class MyMiddle(MiddlewareMixin):
    def process_request(self,request):
        print("fet参数:",request.GET.get("a")

实现阻拦黑名单效果
第一步先在工程目录下新建一个目录自定义名为middleware,在该目录下新建一个有语义的目录比如middleware里新建一个py文件
完成之后还要在setting.py里配置一下
在MIDDLEWARE里添加
class MyappMiddleware的路径

'middleware.middleware.MyappMiddleware',

在末尾添加黑名单列表

#黑名单列表
BLACK_LIST = [
    '192.168.116.1',
]
# 继承于框架中间件
class MyappMiddleware(MiddlewareMixin):
    def process_request(self,request):
        clientIp = request.META['REMOTE_ADDR']
        # # 屏蔽黑名单用户
        # 只要客户端IP在黑名单中
       if clientIp in BLACK_LIST:
            直接渲染fuckoff.html并立刻返回
            return render(request,'fuckoff.html')
    # 下钩子于所有路由请求被交给视图函数之前
    def process_view(self, request, view_func, view_args, view_kwargs):
        print(">>>>>>>>>> process_view", request, view_func, view_args, view_kwargs)

实现会员福利通道
包括登录

所有的钩子函数都可以返回一个Response
一旦钩子函数返回了Response,整个请求的受理就结束了
'''

# 继承于框架中间件
class MyappMiddleware(MiddlewareMixin):

    # 中间件的初始化方法,全局执行一次
    # def __init__(self, get_response=None):
    #     super(MyappMiddleware, self).__init__()
    #     print(">>>>>>>>>> MyappMiddlware __init__")


    # 下钩子于所有路由被交给路由表之前
    def process_request(self, request):

        # 获取客户端IP地址
        clientIp = request.META['REMOTE_ADDR']

        # 请求的路由
        url = request.path
        print(">>>>>>>>>> process_request", request, clientIp, url)

        # # 屏蔽黑名单用户
        # 只要客户端IP在黑名单中
        # if clientIp in BLACK_LIST:
        #     直接渲染fuckoff.html并立刻返回
        #     return render(request,'fuckoff.html')

        # # 当VIP用户访问福利页面时提供更多好的服务
        # if clientIp in VIP_LIST and url=='/myapp/fuli/':
        #     return render(request, 'fuli.html', context={'imgpath': 'meinv1.jpg'})

        # 福利页必须登录了才能查看
        if url == '/myapp/fuli/' and not request.session.get('uname', None):
            return redirect(reverse('myapp:login'))

    # 下钩子于所有路由请求被交给视图函数之前
    def process_view(self, request, view_func, view_args, view_kwargs):
        print(">>>>>>>>>> process_view", request, view_func, view_args, view_kwargs)

    # 理论上下钩子于所有路由请求的模板被渲染完成以后
    # 这个函数实测无法回调
    def process_template_response(self, request, response):
        print(">>>>>>>>>> process_template_response", request, response)
        return response

    # 下钩子于所有路由的响应被返回之前
    def process_response(self, request, response):
        print(">>>>>>>>>> process_response", request, response)
        return response

    def process_exception(self, request, exception):
        print(">>>>>>>>>> process_exception", request, exception)
        return redirect('/')

@上传文件
概述:文件上传时,文件数据存储在request.FILES属性中
存储路径:

  • static目录下创建自定义目录文件upfile用于存储上传的文件
  • 配置路径
    在setting.py 里添加MDEIA_ROOT=os.path.join(BASE_DIR,r’static/upfile’)
    自定义表单格式:
#xxx是提交上传后转到的路由
method='post' action='xxx' enctype='multipart/form-data'> {% csrf_token %} type='file' name='icon'> type='submit' value='上传'>

ps:提交的方式应该用post,由于get只能提交一个网址栏大小的字符串,限定了大小,而post是不限制的
接收的view:

if request.method == 'POST'
    #拿到用户上传的文件数据,类型是框架类InMemoryUploadedFile
    f = request.FILES['icon']
    #f是文件标识符,是文件流
    filePath = os.path.join(settings.MEDIA_ROOT,f.name)
    with open(filePath,'wb') as fp:
        #以文件流的形式接收一段一段的存进文件
        for part in f.chunks():
            fp.write(part)
else:
    return HttpReseponse('上传失败')

@分页
paginator对象,作用是把从数据库提出来的数据进行分割,返回每一块分割好的对象
创建对象

  • 格式:
    Paginator(列表,整数)

  • 返回值
    返回一个分页对象

属性

  • count
    对象总数

  • num_pages
    页面总数

  • page_range
    页码列表,【1,2,3,4,5】,页码从1开始

方法

  • pagen(num)
    获得一个Page对象,如果提供的页码对象不存在会抛出异常’InvaliPage’

异常

  • InvaliPage :当page()传递的是一个无效的页码时抛出
  • PageNotAnlnteger :当page()传递的不是一个整数时
  • EmptyPage:当page()传递一个有效值,但是该页面没有数据时抛出
    Page对象
    创建对象:Paginator对象的page()方法返回page对象,不需要收到创建
    属性:
- object_list:当前页上的数据(对象)列表
 - number:当前页的页码值
 - paginator:当前page对象关联的page对象

方法

has_next():判断是否有下一页,如果有返回True
has_previous():判断是否有上一页,如果有返回True
has_other_pages():判断是否有上一页或下一页,如果有返回True
next_page_number():返回下一页的页码
previous_page_number():返回上一页的页码
len():返回当前页的数据的个数

过程实现:
写view

def studentpage(request,pagenum):
    # 查询数据库获取所有博文
    allstu = Students.object.all()
    # 构建分页器对象,allstu=所有学生,3=每页显示的个数
    paginator =Paginator(allstu,3)
    # 获取第n页的页面对象
    page = paginator.page(pagenum)

    # 将数据丢给页面渲染
    return render(request, 'studentshow.html', {'students':page})

写studentshow.html

<ul>
    #获取页面对象
    {% for stu in students %}
    <li>
        #遍历显示对象属性
        {{stu.name}--{stu.sgrade}}
    li>
    {% endfor %}
ul>
<ul>
    {% for index in students.paginator.page_range %}
        #判断如果显示的是当前页面就不能再点击
        {% if index == students.number %}
            <li>{{index}}li>
        {% else %}
        <li>
            <a href="/app/studentshow/{{ index }}/">{{ index }}a>
        li>
        {% endif %}
    {% endfor %}
ul>

@ajax

作用:需要数据动态生成,请求JSON数据
实现过程:
html页面

#效果:点击按钮显示生成
#导入jquery的js文件

显示学生信息列表

#导入自己写的js文件

自己写的js文件

$(document).ready(function(){
    document.getElementById("btn").onclick =function(){
    $.ajax({
        type:"get",
        #提供数据的路由
        url:"/studentsinfo/",
        dataType:"json",
        success:function(data,status){
            console.log(data)
            var d =data["data"]
            for(var i = 0;i'

'+d[i][o]+'

') } )} } })

路由写法

def studentsinfo(request):
    stus = Students.objects.all()
    list = []
    for stu in stus:
        list.append([stu.sname,stu.sage])
    return JsonResponse({'data':list})

返回的数据可以使用生成标签
@富文本
作用是把标签textarea标签变成文本编辑器,用于编写博客时,,,,,,
第一步
安装pip install django-tinymce
第二步
站点中使用:
1,配置setting.py中的INSTALL_APP 里添加‘tinymce’
后尾再增加

TINYMCE_DEFAULT_CONFIG={
    'theme':'advanced',
    'width':600,
    'height':400,
    #宽和高都是自定义的
}

2,新建一个Text模型

from tinymce.models import HTMLField
class Text(models,Model):
    str = HTMLField()

3,数据迁移后再admin里注册一下就可以在站点管理里使用了
@自定义视图中使用
重点是html的编写

#这个JS是写死的
<script src="/static/tiny_mce/tiny_mce.js" type="text/javascript" charset="utf-8">script>
<script type="text/javascript">
    tinyMCE.init({
        'mode':'textareas',
        'theme':'advanced',
        'width':800,
        'height':600
        })
script>
#boby部分


<form action='提交路由'>
    <textarea name=''str>文本编写的内容textarea>
form> 

你可能感兴趣的:(django)