努力理解 Django 中的 WSGI 接口

San*_*idi 1 django wsgi

我最近试图了解什么是 WSGI 应用程序:

WSGI 应用程序只是一个可调用对象,它传递一个环境 - 一个包含请求数据的字典,以及一个被调用以开始发送响应的 start_response 函数。

为了将数据发送到服务器,您所要做的就是调用 start_response 并返回一个可迭代对象。

所以,这是一个简单的应用程序:

def application(environ, start_response):
    start_response('200 OK', [('Content-Type', 'text/html')])
    return ['Hello World!']
Run Code Online (Sandbox Code Playgroud)

Django 的 wsgi.py 是

"""
WSGI config for basic_django project.

It exposes the WSGI callable as a module-level variable named ``application``.

For more information on this file, see
https://docs.djangoproject.com/en/2.2/howto/deployment/wsgi/
"""
import os

from django.core.wsgi import get_wsgi_application

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'basic_django.settings')

application = get_wsgi_application()
Run Code Online (Sandbox Code Playgroud)

但是当我看到 wsgi.py 时,application = get_wsgi_application()可调用对象没有通过environstart_response函数传递

那么如何理解这一点

Ama*_*dan 5

您无法看到传递给什么内容application- 这是 WSGI 容器的工作,而不是您的工作。您的定义是可以 传递application这两个参数的东西。

有多种方法可以创建可调用对象。最简单的是一个函数:

def add5(x):
    return x + 5
Run Code Online (Sandbox Code Playgroud)

另一种是匿名函数,或 lambda:

add5 = lambda x: x + 5
Run Code Online (Sandbox Code Playgroud)

还有一个是具有方法的类的对象__call__

class AdderOf5:
    def __call__(self, x):
        return x + 5

add5 = AdderOf5()
Run Code Online (Sandbox Code Playgroud)

您可以将其中任何一个包装到返回可调用对象的函数中:

def make_add_y(y):
    def add_y(x):
        return x + y
    return add_y
add5 = make_add_y(5)
Run Code Online (Sandbox Code Playgroud)

或者

def make_add_y(y):
    return lambda x: x + y
add5 = make_add_y(5)
Run Code Online (Sandbox Code Playgroud)

第三个选项并不完全需要包装器,因为该类已经是一个工厂:

class AdderOfY:
    def __init__(self, y):
        self.y = y

    def __call__(self, x):
        return x + self.y

add5 = AdderOfY(5)
Run Code Online (Sandbox Code Playgroud)

我想我们甚至可以创建一个函数来构造一个可调用对象并将其返回给我们:

class AdderOfY:
    def __init__(self, y):
        self.y = y

    def __call__(self, x):
        return x + self.y

def make_adder(y):
    return AdderOfY(5)

add5 = make_adder(5)
Run Code Online (Sandbox Code Playgroud)

所有这些都展示了如何定义可调用对象。如何调用可调用对象是另一段代码,而且无论可调用对象的定义方式如何,它看起来都是一样的:

eight = add5(3)
Run Code Online (Sandbox Code Playgroud)

无论我们以哪种方式构造,您都可以尝试验证这条线是否有效add5


回到 WSGI:您提供的示例创建了一个接受两个参数的简单函数。

Django 的get_wsgi_application函数是一个包装器,它返回相同形式的可调用函数:可以给定环境并启动响应。

如果您想了解它是如何定义的,它的外观如下:

get_wsgi_application

def get_wsgi_application():
    # ...
    return WSGIHandler()
Run Code Online (Sandbox Code Playgroud)

WSGIHandler

class WSGIHandler(base.BaseHandler):
    # ...
    def __call__(self, environ, start_response):
        # ...
Run Code Online (Sandbox Code Playgroud)

您可以注意到它看起来与我的上一个示例几乎完全相同:构造可调用对象的函数。可以使用两个参数来调用可调用对象:environstart_response

在调用方面,它不在您的代码中,而是在 WSGI 容器中(例如 Apache 的mod_wsgi,或在 gUnicorn...),无论您使用简单的函数(如第一个示例中所示)还是使用可调用对象(就像在 Django 中一样):

response = application(environ, start_response)
Run Code Online (Sandbox Code Playgroud)