美文网首页
Django中间件与上下文渲染器

Django中间件与上下文渲染器

作者: Python野路子 | 来源:发表于2018-04-21 22:46 被阅读0次

django中一个请求的流程

我们从浏览器发出一个请求 Request,得到一个响应后的内容 HttpResponse ,这个请求传递到 Django的过程如下:


image.png

也就是说,每一个请求都是先通过中间件中的 process_request 函数,这个函数返回 None 或者 HttpResponse 对象,如果返回前者,继续处理其它中间件,如果返回一个 HttpResponse,就处理中止,返回到网页上。

Django中间件(Middleware)

  • 中间件,顾名思义,就是处在中间的一些软件。比如匹配到了URL,但是还没有执行view函数的时候,这个时候可以执行一些代码,这个代码就是中间件。
  • Django已经内置了许多中间件,这些中间件已经可以满足90%以上的需求,如果还不够,还可以定义自己的中间件,以下将对Django自带的中间件进行详细解释,自带在settings.py中MIDDLEWARE配置:


    image.png
  1. django.middleware.security.SecurityMiddleware:一些安全设置,比如XSS脚本过滤。
  2. django.contrib.sessions.middleware.SessionMiddleware:session支持中间件,加入这个中间件,会在数据库中生成一个django_session的表。
  3. django.middleware.common.CommonMiddleware:通用中间件,会处理一些URL,比如baidu.com会自动的处理成www.baidu.com。比如/blog/111会处理成/blog/111/自动加上反斜杠。
  4. django.middleware.csrf.CsrfViewMiddleware:跨域请求伪造中间件。加入这个中间件,在提交表单的时候会必须加入csrf_token,cookie中也会生成一个名叫csrftoken的值,也会在header中加入一个HTTP_X_CSRFTOKEN的值来放置CSRF攻击。
  5. django.contrib.auth.middleware.AuthenticationMiddleware:用户授权中间件。他会在每个HttpRequest对象到达view之前添加当前登录用户的user属性,也就是你可以在view中通过request访问user。
  6. django.contrib.messages.middleware.MessageMiddleware:消息中间件。展示一些后台信息给前端页面。如果需要用到消息,还需要在INSTALLED_APPS中添加django.contrib.message才能有效。如果不需要,可以把这两个都删除。
  7. django.middleware.clickjacking.XFrameOptionsMiddleware:防止通过浏览器页面跨Frame出现clickjacking(欺骗点击)攻击出现。

中间件执行顺序

  • 在调用视图前,按照settings中配置的MIDDLEWARE顺序执行
  • 在调用视图后,中间件会按相反的顺序执行

编写一个自定义的中间件

  • 你可以定义一个独立的python类来作为一个自定义中间件
  1. __init__(self, get_response):
    中间件的初始化只会在django启动时调用一次,并且只接受get_response函数,所以一般都不会去重写它
    def __init__(self,get_response):
        #get_response其实就是我们的view function
        self.get_response = get_response

2.__call__(self, resquest):

def __call__(self, request):
    # 在这里编写执行view视图需要处理的代码    
    response = self.get_response(request)
  # 在这里编写执行view视图后需要处理的代码
    return response

ps: response = self.get_response(request) 必须要有
settings.py中添加自定义的中间件:

添加
# -*- coding: utf-8 -*-
from django.http import HttpResponseForbidden, HttpResponseBadRequest, HttpResponseServerError
#原生中间件
class MiddleWareTest:
    def __init__(self,get_response):
        #get_response其实就是我们的view function
        self.get_response = get_response
        self.count = {}
    def __call__(self,request):
        print('view执行之前')
        # 在这里编写执行view视图需要处理的代码
        # 防止访问频率过高
        #有些网站服务器会使用ngix等代理http,或者是该网站做了负载均衡,导致使用remote_addr抓取到的是1270
        #这时使用HTTP_X_FORWARDED_FOR才获得是用户的真实IP。推荐使用以下代码:
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            ip = request.META['HTTP_X_FORWARDED_FOR']
            print(ip)
        else:
            #使用django来获取用户访问的IP地址,如果用户是正常情况下
            ip = request.META['REMOTE_ADDR']

        count = self.count.get(ip,0) #不存在则返回自定的0,存在则返回ip对应的值;

        if count and count > 3:
            #其实就是返回403拒绝访问
            return HttpResponseForbidden
        else:
            count += 1
            self.count[ip] = count
            #这段代码其实就是执行我们的view视图
            response = self.get_response(request)

            # 这里编写你需要的请求之后的处理
            print('view执行之后')
            return response
#中间件除了类的方法,还可以用function
  • 在调用视图前,他有以下函数
    process_view(request, view_func, view_args, view_kwargs): return None or HttpResponse
  • 调用视图之后
    process_template_response(request, response): return 实现了render方法的HttpResponse
    如果需要调用这个函数,返回的response必须包含render方法,一般该函数做模版内容处理
    process_exception(request, exception): return None or HttpResponse
    该请求在报出异常时,执行该方法
from django.http import HttpResponseForbidden, HttpResponseBadRequest, HttpResponseServerError
from django.utils.deprecation import MiddlewareMixin
class MiddleWareTest(MiddlewareMixin):
    def process_view(self, request, view_func, view_args, view_kwargs):
        """
            @request, 当前请求对象
            @view_func, 就是我们需要执行的view_func方法,
            @view_args, 就是我们的view_func所带的位置参数
            @view_kwargs, 就是我们的view_func所带的键值参数
        """
        print('process_view')
        response = view_func(request,*view_args,**view_kwargs)
        # 这个方法如果返回的是一个response, 它就提前结束请求
        return response

    def process_template_response(request, response):

        print('process_template_response')
        return response

    def process_exception(self, request, exception):
        # 这个异常必须是在执行view中出现的异常,它才能进入这个里面

        print('----exception----------')

中间件开发准则

  • 不能继承自任何类(可以继承 object )
  • 中间件可以存在于你Python 路径中的任何位置。 Django所关心的只是被包含在MIDDLEWARE中的配置。
  • 将Django 中可用的中间件作为例子随便看看。https://docs.djangoproject.com/en/1.11/ref/middleware/
  • 如果你认为你写的中间件组建可能会对其他人有用,那就把它共享到社区! 让我们知道它,我们会考虑把它添加到Django中
  • 中间件一般是实现一个系统级别的应用或者面向整个工程应用,所以一般情况下,中间件不能有业务代码

使用中间件开发流量统计

  1. 添加一个middleware类
    你创建的类原则上是可以放置在任何路径,只要你能够引用,如果你要写自己的中间件,我们一般会在某个app下添加一个middleware文件或者创建一个文件夹,专门存储中间件文件

'''
流量统计
'''
class StatFlowMiddleware(object):
    def __init__(self,get_response):
        self.get_response = get_response
        self.filename = 'count.txt'
    def __call__(self, request):
        # 获取IP
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            ip = request.META['HTTP_X_FORWARDED_FOR']
        else:
            ip = request.META['REMOTE_ADDR']
        with open(self.filename,'a+') as f:
            f.seek(0)
            content = f.read()
        if content:
            content = json.loads(content) #序列化,将json格式转换为python对象
            count = content.get(ip)
            if count > 5:
                return HttpResponseForbidden()
            # 这段代码其实就是执行我们的view视图
            response = self.get_response(request)
            # 只有这个请求返回为200,才代表这个请求需要被统计
            if response.status_code == 200:
                if content:
                    content[ip] = content[ip] + 1
                else:
                    content = {ip: 1}
                with open(self.filename, "w+") as f:
                    f.write(json.dumps(content)) #反序列化,python对象转化为json格式
            return response
  1. 添加至settings.py
    image.png

Django上下文渲染器

有时候我们想让一些内容在多个模板中都要有,比如导航内容,我们又不想每个视图函数都写一次这些变量内容,怎么办呢?这时候就可以用 Django 上下文渲染器来解决。

  • 内置的上下文渲染器 image.png
django.template.context_processors.debug: 测试模块
debug - True。你可以在模板中用它测试是否在DEBUG 模式。
sql_queries –  一个{'sql': ..., 'time': ...} 字典的列表,表示请求期间到目前为止发生的每个SQL 查询及花费的时间。这个列表按查询的顺序排序,并直到访问时才生成。
django.template.context_processors.request: 处理请求模块
requset - 表示当前的HttpRequest。
django.contrib.auth.context_processors.auth: django内置的用户登录管理
user – 一个 auth.User实例代表当前登录的用户 (或者 一个 AnonymousUser 实例, 如果用户没有登录).
perms – 一个 django.contrib.auth.context_processors.PermWrapper实例, 代表当前登录用户所拥有的权限.
django.contrib.messages.context_processors.messages:
messages – 通过消息框架设置的消息(字符串形式)列表。
DEFAULT_MESSAGE_LEVELS – 消息等级名称到它们数值 的映射。
学以致用
  1. 使用中间件完成数据统计,每个IP只统计一次,看看每分钟有多少个IP访问当前网站。
  • 开发中间件middleware.py
import datetime
'''
使用中间件完成数据统计,每个IP只统计一次,看看每分钟有多少个IP访问当前网站;
1.获取访问ip,然后写入到文件里面去;
如果文件里面存在,那么不写入;
'''
class StatisticsIpware:
    startTime = datetime.datetime.now()
    file = 'count.txt'
    count = 0
    def __init__(self,get_response):
        self.get_response = get_response
    def __call__(self, request):
        #获取ip
        if 'HTTP_X_FORWARDED_FOR' in request.META:
            ip = request.META['HTTP_X_FORWARDED_FOR']
        else:
            ip = request.META['REMOTE_ADDR']
        with open(StatisticsIpware.file,'a+') as f: #a+ 若文件存在,则文件指针将位于结尾,若该文件不存在,创建新文件用于读写。
            f.seek(0)  #将指针移动到开头,以便read从开头到末尾读取
            content = f.read()
        # 这段代码其实就是执行我们的view视图
        response = self.get_response(request)
        #执行view后执行
        self.visiTime = datetime.datetime.now()
        spaceTime = (self.visiTime - StatisticsIpware.startTime).seconds #利用求出时间差,seconds获取秒
        if response.status_code == 200:
            if spaceTime <= 30: #如果时间差小于1分钟
                print(ip)
                if ip not in content: #如果不存在ip
                    with open(StatisticsIpware.file,'a+') as f:
                        f.write('{},'.format(ip)) #则写入
                        StatisticsIpware.count += 1
            else:
                print('当前访问量1分钟{}'.format(StatisticsIpware.count))
        return response
  • settings.py配置中间件 image.png
  1. 使用上下文渲染器完成首页菜单栏
  • 定义上下文渲染器context_processors.py
# -*- coding: utf-8 -*-
def menu_bar(request):
    return {'first':u'首页','second':u'基础教程','third':u'项目实战','fourth':u'每日一练'}

def my_ip(request):
    # 获取ip
    if 'HTTP_X_FORWARDED_FOR'  in request.META:
        ip = request.META['HTTP_X_FORWARDED_FOR']
    else:
        ip = request.META['REMOTE_ADDR']
    return {'IP':ip}
  • 上下文渲染器 加入到settings.py 中:
    image.png
  • 页面模板:
    基础模板menu_base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}菜单模板{% endblock %}</title>
    <style>
        * {
            margin: 0;
            padding: 0;
        }
        #menu_div{
            width: 100%;
            height: 50px;
            background: rgba(0,0,0,0.8);
        }
        #ip_div{
            position: absolute;
            bottom: 30px;
            color: indianred;
        }
        .menu_bar{
            list-style: none;
            margin-left: 60px;
        }
        li{
            float: left;
            padding-left: 60px;
            color: white;
            line-height: 50px;
            text-align: center;
        }
    </style>
</head>
<body>
<div id="menu_div">
    <ul class="menu_bar">
        <li>{% block li_first%}{% endblock %}</li>
        <li>{% block li_second%}{% endblock %}</li>
        <li>{% block li_third%}{% endblock %}</li>
        <li>{% block li_fourth%}{% endblock %}</li>
    </ul>
</div>
<div id="ip_div">访问ip:<span>{% block ip%}{% endblock %}</span></div>
</body>
</html>

首页indexpage.html

{% extends "menu_base.html" %}
{% block title %}首页{% endblock %}
{% block li_first%}{{first}}{% endblock %}
{% block li_second%}{{second}}{% endblock %}
{% block li_third%}{{third}}{% endblock %}
{% block li_fourth%}{{fourth}}{% endblock %}
{% block ip %}{{IP}}{% endblock %}

主页·homepage.html

{% extends "menu_base.html" %}
{% block title %}主页{% endblock %}
{% block li_first%}{{first}}{% endblock %}
{% block li_second%}{{second}}{% endblock %}
{% block li_third%}{{third}}{% endblock %}
{% block li_fourth%}{{fourth}}{% endblock %}
{% block ip %}{{IP}}{% endblock %}
效果: image.png
image.png

相关文章

  • Django中间件与上下文渲染器

    django中一个请求的流程 我们从浏览器发出一个请求 Request,得到一个响应后的内容 HttpRespon...

  • Django 中间件

    1.什么是Django的中间件? django 中的中间件(middleware),在django中,中间件其实就...

  • Django源码分析

    wsgi与request、response urlresolve与中间件 django ORM template体...

  • 13.中间件和上下文处理器

    中间件 中间件的引入image.png django中的中间件django 中的中间件(middleware),在...

  • 什么是Django中的中间件?

    什么是Django中的中间件? 中间件 Django中的中间件是一个轻量级、底层的插件系统,可以介入Django的...

  • Django_中间件

    Django的中间件的简介 Django的中间件类似于linux中的管道符Django的中间件实质就是一个类,类之...

  • django middleware

    参考:Django 源码学习(3)——中间件Django Middleware官方文档Django==2.0.4源...

  • Django的生命周期

    Django的生命周期 一. Django HTTP请求流程图 二. 中间件 什么是中间件 中间件是一个用来处理D...

  • Django 十一

    目录 1.cbv加装饰器 总结 2.中间件介绍和常用内置中间件 3.django内置中间件 4.django自定义...

  • Django中间件和上下文处理器

    中间件的引入:Django中间件(Middleware)是一个轻量级、底层的“插件”系统,可以介入Django的请...

网友评论

      本文标题:Django中间件与上下文渲染器

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