使用中间件为django中的视图函数添加参数

Using middleware to add arguments to view functions in django

我有一个非常小的基本站点,只有少量视图。几乎所有的视图都与外部 API.

进行了一些交互

在每个视图中,我都实例化了我的 API class 的一个对象,这显然不是很 DRY。我还有一个中间件,可以向请求对象添加一个或两个有用的变量(我的中间件在链中最后运行)。

我想在中间件中实例化我的 api class,然后将其作为参数传递给每个视图,即

def my_view(request, my_api_class_instance):

然后从中间件调用视图,例如:

def process_view(self, request, view_func, view_args, view_kwargs):
    my_api = api(some, args, here)
    response = view_func(request, my_api, *view_args, **view_kwargs)
    return response

这似乎是一种快速简便的整理代码和减少重复的方法。这有什么本质上不好的地方吗?

您可以使用中间件,但还有其他两种可能性,两者都更灵活。第一个是使用装饰器并包装视图:

@my_api_init_decorator
def my_view(request, my_api):
    ...

这允许您在初始化 api...

之前显式 select 查看、检查用户授权或权限

第二种解决方案是使用基于 class 的视图并创建您自己的继承视图。

如果您查看 Django 中间件 documentation,您会看到;

If process_view returns an HttpResponse object, Django won’t bother calling any other view or exception middleware, or the appropriate view; it’ll apply response middleware to that HttpResponse, and return the result.

因此返回一个 HttpResponse 将跳过其他中间件 类 在这个中间件下面的执行 通常应该避免 除非你的中间件是 settings.MIDDLEWARE_CLASSES 列表.

但是,您仍然可以将 API 对象绑定到传递给中间件的 HttpRequest 实例。这与 AuhenticationMiddleware 填充 request.user.

的方法相同
def APIMiddleware(object):
    def process_request(self, request):
        request.api = API(host, port, user, password, extra={"url": request.get_full_path()})

你可以在中间件

中更改view_kwargs
class SomeMiddleware(object):
    def process_view(self, request, view_func, view_args, view_kwargs):
        view_kwargs['my_api'] = api(some, args, here)
        return None

def my_view(request, my_api):
    # you can use you api there
def my_view(request, args, my_api)
    # you can use you api there

document it's there 中间件 returns None,Django 将继续处理此请求,执行任何其他 process_view() 中间件。

但是,这只适用于每个视图函数都可以得到关键字参数'myapi',否则会引发 TypeError。

所以最好的方法不是通过 func 参数传递你的 api,就像@ozgur 通过请求传递你的 api。