在Django中是否有相当于Flask的“@ app.errorhandler”?

时间:2016-06-02 17:31:30

标签: python django error-handling flask

我正在编写多个视图,并希望验证请求正文。常见的情况是主体必须是存在某些键的JSON对象。我写了一个视图,并有这段代码:

try:
    body = json.loads(request.body)
except ValueError:
    return InvalidInputResponse("Could not load request body")

if not isinstance(body, dict):
    return InvalidInputResponse("Request body was not a JSON object")

if set(body.keys()) != {'author', 'title', 'content'}:
    return InvalidInputResponse("Request object missing keys")

InvalidInputResponsehttp.HttpResponse的子类。

我想在其他视图中重复使用此代码。我真正想做的是:

body = process_body(request.body, required_keys={'author', 'title', 'content'})
# rest of code here ...

但是,正如代码现在,我无法做到这一点。我必须这样做:

body = process_body(request.body, required_keys={'author', 'title', 'content'})
if isinstance(body, http.HttpResponse):
    return body
# rest of code here ...

这有点难看。

在Flask中,我可以创建一个名为InvalidInputException的自定义异常,然后register an error handler for it ...比如说:

@app.errorhandler(InvalidInputException)
def handle_invalid_input(error):
    return InvalidInputResponse(error.reason)

Django中是否有等效的机制?如果没有相应的机制,那么处理这个问题的方法是什么?

1 个答案:

答案 0 :(得分:2)

Django也有自定义异常处理程序。它们可以附加via middleware

class InvalidInputMiddleware(object):
    def process_exception(self, request, exception):
        if isinstance(exception, InvalidInputException):
             return InvalidInputResponse(exception.reason)

        return None

Django将返回任何中间件返回的第一个响应。请注意,响应阶段以相反的顺序运行中间件。

如果全球使用,只需添加到MIDDLEWARE_CLASSES的末尾即可。对于非全局案例,我使用了一个(略微邪恶的)middleware_on_class猴子修补程序来完成这项工作:

from functools import wraps
from django.utils.decorators import (
    decorator_from_middleware,
    method_decorator
)

def middleware_on_class(middleware):
    def decorator(cls):
        dispatch = cls.dispatch

        @wraps(dispatch)
        @method_decorator(decorator_from_middleware(middleware))
        def wrapper(self, *args, **kwargs):
            return dispatch(self, *args, **kwargs)

        cls.dispatch = wrapper
        return cls
    return decorator

用作

handle_invalid_input = middleware_on_class(InvalidInputMiddleware)

@handle_invalid_input
class View(...):
    pass