最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

Django2:Web项目开发入门笔记(24)

Django教程 小楼一夜听春语 5371浏览 0评论

这一篇教程,我们一起来了解Django的上下文处理器(Context Processor)和中间件(Middleware)。

对于这两块内容,我们最好先了解概念和原理,才能比较好的去应用它们。

一、上下文处理器(Context Processor)

上下文处理器也称作上下文渲染器。

我个人认为处理比渲染更容易理解,而且英文中“Processor”的意思是处理,“Render”的意思是渲染。

但是称为上下文渲染器也有道理,渲染更接近于使用场景。

Django中的Context Processor主要是应用于模板,完成页面的绘制的一些处理,也就是所说的页面渲染。

还有,上下文又是什么?

这个概念,感觉很难懂。

从语文的角度来说,上下文是语境;

同一句话,在不同的语境中,会有不同的意思。

例如,小明考试成绩100分,爸爸说“干得漂亮”,这是表扬的意思。

而小明考试成绩0分,爸爸说“干得漂亮”,这是讽刺的意思。

所以,同样的一句话,我们需要和上文联系到一起才能明白真正的意思。

从计算机编程角度来说,上下文是环境。

也就是说,同一段处理程序对于不同的环境,反馈出不同的处理结果。

借用网上的一个例子:用户访问站点的时候,站点的所有页面上都要能够显示这个用户自己的IP地址。

这样的功能,我们需要从请求(request)中获取到访问用户的IP地址,然后呈现到页面中。

也许大家能够想到,我们可以在每个页面对应的视图函数中进行这个处理,但是未免太过麻烦。

最好的方式是将处理过程定义一次,就能够在每个页面中使用。

此时,我们可以通过自定义一个上下文处理器帮助我们完成。

面对不同来源的用户通过同一个处理器完成页面上不同IP地址的渲染。

1、创建上下文处理器

在项目文件夹(“wsgi.py”所在的文件夹)新建一个文件“context_processor.py”。

在这个文件中添加获取用户IP地址的代码。

示例代码:

def getuserip(request):
    ip = request.META['REMOTE_ADDR']
    if ip == '127.0.0.1':
        return {'user_type': '本机用户'}
    return {'user_type': '外部用户(%s)' % ip}

注意:上下文处理器必须返回一个字典。

2、将上下文处理器添加到模板设置

打开文件“settings.py”,在模板设置中添加处理器中的函数。

TEMPLATES = [
    {
        ...省略部分代码...
        'OPTIONS': {
            'context_processors': [
                ...省略部分代码...
                'MyProject.context_processor.getuserip'
            ],
        },
    },
]

上方代码中,红色部分为新增代码。

3、在页面模板中添加标记

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>首页</title>
</head>
<body>
当前访问用户:{{ user_type }}
</body>
</html>

完成上述代码后,Django调用模板时会先通过上下文处理器进行处理,并将处理后返回的数据字典传入模板,通过模板标记获取数据。

此时,我们就可以打开开发服务器,进行访问测试了。

注意:如果需要允许外部访问,需要监听所有IP地址,服务器启动命令为:runserver 0.0.0.0:端口号,也可以简写为runserver 0:端口号(Win10无效)

本机访问结果:

外部访问结果:(例如手机)

二、中间件(Middleware)

中间件,我们需要搞清楚它在什么中间,起到什么作用?

根据官方文档的说法,中间件是请求(request)与响应(response)之间的钩子(hooks)框架。

…又多了个钩子。

个人理解钩子实际上就是挂在主程序上的监控程序,当主程序运行中满足了钩子的触发条件时,执行钩子的处理程序。

在官方文档中,给出的中间件示例非常简单直观,并且包含了两种写法。

1、以函数的形式定义中间件。

示例代码:

def simple_middleware(get_response):
    # One-time configuration and initialization.

    def middleware(request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

    return middleware

2、以类的形式定义中间件

class SimpleMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response
        # One-time configuration and initialization.

    def __call__(self, request):
        # Code to be executed for each request before
        # the view (and later middleware) are called.

        response = self.get_response(request)

        # Code to be executed for each request/response after
        # the view is called.

        return response

那么,中间件怎么使用?能起到什么样的作用呢?

依然通过举例说明。

例如,我们发布的项目只允许本机和指定ip访问,不允许外部其他地址的设备访问,就可以通过中间件来实现。

首先,创建一个中间件文件“middleware.py”,并定义访问限制的中间件。

这个文件可以创建一个新的Package进行存放,例如:MW。

示例代码:

from django.http import HttpResponseForbidden

class AaccessRestrictionMiddleware:

    def __init__(self, get_response):
        self.get_response = get_response
        self.wite_ip = ['127.0.0.1', '192.168.31.18']  # 初始化ip地址白名单

    def __call__(self, request):
        ip = request.META['REMOTE_ADDR']  # 获取访问用户的ip
        if ip not in self.wite_ip:  # 如果ip不在白名单中
            return HttpResponseForbidden('您被禁止访问!')  # 返回响应
        response = self.get_response(request)
        return response

然后,我们打开文件“settings.py”,在中间件设置中添加中间件的类。

示例代码:

MIDDLEWARE = [
    'MW.middleware.AaccessRestrictionMiddleware',
    ...省略其他中间件...
]

通过以上操作,我们就可以限制只有IP白名单中的用户才能够访问我们的项目。

中间件比较像游戏的外挂程序,游戏主程序的执行过程中一旦满足触发外挂的情形出现,外挂就会执行相应的处理。但是,外挂并不会改变主程序,当我们不需要外挂的时候,只需要移除外挂程序,主程序依然能够正常的执行。

本节练习源代码:【点此下载

转载请注明:魔力Python » Django2:Web项目开发入门笔记(24)

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)

网友最新评论 (2)

  1. 头像
    程序能跑。但源码链接挂了,关系不是很大。
    走路爱走神6年前 (2018-06-11)回复
    • 小楼一夜听春语
      已修复,谢谢!发的时候写错文件名了。
      小楼一夜听春语6年前 (2018-06-11)回复