Django中对异常的处理
Django中对request的处理
- 首先执行
process_request
函数,然后在执行视图函数之前执行process_view
函数,再执行视图函数,最后执行process_response
函数 process_request
只返回None
,所有中间件的process_request
执行完之后,就匹配路由,找到对应的视图函数,在执行视图函数之前先执行中间件的process_view
函数- 如果
process_view
返回 None,就继续执行后续的中间件的process_view
方法,执行完所有的process_view
函数之后执行视图函数 - 如果其中有个 process_view 返回了 HttpResponse,就不执行后续的 process_view 函数,会跳到第一个 process_response 函数,并继续往下执行
中间件(类)中5种方法
中间件中可以定义5个方法:
- process_request(request)
- process_view(request, view_func, view_args, view_kwargs)
- process_exception(request, exception)
- process_template_response(request, response)
- process_response(request, response)
process_request
- 中间件在收到
request
请求之后执行 - 按照
settings.py
中MIDDLEWARE_CLASSES
的顺序,顺序执行 - 如果该函数返回
None
,继续执行后面的中间件的process_request
方法 - 如果该函数返回
HttpResponse
,则不再继续执行后面的中间件的process_request
方法
process_view
- 执行完所有中间件的
process_request
方法 - 在
urls.py
中找到对应视图函数 - 拿到视图函数的名称、参数,在执行视图函数之前执行
- 如果返回
None
,则继续执行后面的中间件的process_view
函数,然后执行下昂应的视图函数 - 如果返回
HttpResponse
,则不执行后续的process_view
函数,也不执行视图函数,然后执行所有的response
中间件
process_exception
- 执行视图函数的过程中如果引发异常,则按照
settings.py
中MIDDLEWARE_CLASSES
的顺序,倒序执行process_exception
方法 - 如果返回
None
,继续执行下一个中间件的process_exception
方法 - 如果返回
HttpReponse
对象,则该中间件上方其他中间件的process_exception
方法不会被调用 - 一旦其中某个中间件有返回值,则调用
template_response
和response
中间件
,否则启动默认的异常处理
最后半句个人理解:如果如果所有中间件的
process_exception
方法都执完后还没有返回值,则启动默认的异常处理
process_template_response
- 在视图函数执行结束之后执行
response
是Django视图或者某一中间件的返回值(TemplateResponse
对象或等价)- 只有
response
实现了render
方法才会执行 - 一旦所有的中间件的
template_response
被执行完,则调用render
方法 - 按照中间件的顺序,倒序执行
process_response
- 在视图函数执行结束之后执行
- 必须有返回值,且返回类型必须是
HttpResponse
对象 - 按照中间件的顺序,倒序执行
代码实现
文件
middleware.py
from django.utils.deprecation import MiddlewareMixin from django.models import models from django.core.serializers.json import DjangoJSONEncoder from django.http import JsonResponse class MyMiddleware(MiddlewareMixin): def process_exception(self, request, exception): if not isinstance(exception, BaseException): if settings.DEBUG: return JsonResponse({'result': '', 'msg': str(exception), 'status': 1000}) else: return JsonResponse(UnknownException().as_dict()) else: return JsonResponse(exception.as_dict()) def process_response(self, request, response): procese_type = (list, tuple, dict, str, int) if isinstance(response, models.Model): response = str(response) if isinstance(response, procese_type): ret = {'result': response, 'msg': 'success', 'status': 200} return JsonResponse(ret, encoder=DjangoJSONEncoder) else: return response
exceptions.py
from abc import ABCMeta from .message import ErrorMsg class InterFaceAsDictInterFace: def as_dict(self): ret = {'result': '', 'msg': getattr(self, '__msg__', ''), 'status': getattr(self, '__status__', '')} return ret class BaseException(Exception, InterFaceAsDictInterFace): __metaclass__ = ABCMeta def __init__(self, msg=None): super(BaseException, self).__init__() if msg is not None: self.__msg__ = msg class UnknownException(InterFaceAsDictInterFace): __status__ = 1000 __msg__ = ErrorMsg.UNKNOWN_EXCEPTION class MyException(BaseException): __status__=1001 __msg__=ErrorMsg.MY_EXCEPTION
message.py
from django.utils.translation import gettext as _ class ErrorMsg: UNKNOWN_EXCEPTION= _('Unknown exception.') MY_EXCEPTION = _('Test exception.')
修改settings文件
修改setting
中的MIDDLEWARE_CLASSES
变量
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', 'middleware.MyMiddleware', ]
Todo
对前端Post请求进行参数校验
目前想出来了两种策略(假设post_json
为序列化后的字典):
视图函数中使用
get
从字典中获取参数,判断required
的参数是否为空,raise
自定义的异常,如:# exception.py ... class ValidationError(BaseException): __msg__ = ErrorMsg.INVALID_ARGUMENT __status__ = 1001 ... # message.py class ErrorMsg: UNKNOWN_EXCEPTION= _('Unknown exception.') INVALID_ARGUMENT = _('Invalid arguments.') REQUIRED_ARGUMENT = _('A {0} argument is required.') # view.py def test(request): ... user_name = post_json.get('username','')# required pass_word = post_json.get('password','')# required user_type = post_json.get('user_type','')# not required if not username or not password: raise ValidationError(ErrorMsg.REQUIRED_ARGUMENT.format('username/passswordd')) ...
视图函数中对参数不做校验,只需在中间件添加一句,即可对视图函数中
raise
的KeyError
进行统一处理# exception.py ... class ValidationError(BaseException): __msg__ = ErrorMsg.INVALID_ARGUMENT __status__ = 1001 ... # middleware.py ... def process_exception(self, request, exception): if isinstance(exception, KeyError): exception = ValidationError(ErrorMsg.REQUIRED_ARGUMENT.format(exception)) ... # message.py class ErrorMsg: UNKNOWN_EXCEPTION= _('Unknown exception.') INVALID_ARGUMENT = _('Invalid arguments.') REQUIRED_ARGUMENT = _('A {0} argument is required.') # view.py def test(request): ... user_name = post_json['user_name'] # required user_type = post_json.get('user_type','')# not required ...
视图函数返回
目前视图函数必须有返回值,不能为None
,还不知道怎么解决
全部评论
(1) 回帖