Django请求处理过程的逻辑基本上在django.core.handlers.base.BaseHandler这个类的get_response方法中了,为了简单起见,我只是截取了这个类的部分代码,并把相应的过程作为注释写在代码里,说明问题即可。(本代码截取于Django 1.4)
1. 接收到一个请求(初始化)
2. 应用请求中间件(中间件第一回合)
3. 应用视图中间件(中间件第二回合)
4. 调用用户视图方法
5. (如果有异常发生的话)应用异常处理中间件(中间件第三回合)
6. (如果符合要求的话)应用模板中间件(中间件第四回合)
7. 应用响应中间件(中间件第五回合)
8. (如果中间没有异常发生的话)最终响应用户请求
代码分析如下:
class BaseHandler(object):
...
def get_response(self, request):
from django.core import exceptions, urlresolvers
from django.conf import settings
try:
urlconf = settings.ROOT_URLCONF
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
try:
response = None
# 应用请求中间件(第一回合)
# 这是中间件的第一回合,一般来说,中间件返回None,则表示继续往下一级处理,否
# 则,响应已完成,不再进行处理,因此每次处理之前,都有"response is None"的
# 判断。
for middleware_method in self._request_middleware:
response = middleware_method(request)
if response:
break
if response is None:
# 处理Request对象中的urlconf,可以来实现类似URL重写的功能
if hasattr(request, urlconf):
# Reset url resolver with a custom urlconf.
urlconf = request.urlconf
urlresolvers.set_urlconf(urlconf)
resolver = urlresolvers.RegexURLResolver(r'^/', urlconf)
# 提取出用户视图方法,随后调用
callback, callback_args, callback_kwargs = resolver.resolve(
request.path_info)
# 应用视图中间件(第二回合)
for middleware_method in self._view_middleware:
response = middleware_method(request, callback,
callback_args, callback_kwargs)
if response:
break
if response is None:
# 调用用户视图方法
try:
response = callback(request, *callback_args,
**callback_kwargs)
except Exception, e:
# 应用异常处理中间件(第三回合)
# 这里的异常处理中间件只处理调用户视图产生的异常,并不是所有的异常。
for middleware_method in self._exception_middleware:
response = middleware_method(request, e)
if response:
break
if response is None:
raise
# 完成以上步骤后,response不应该为空了,否则就要抛出异常
if response is None:
try:
view_name = callback.func_name # If it's a function
except AttributeError:
view_name = callback.__class__.__name__ + '.__call__'
raise ValueError(The view %s.%s didn't return an
HttpResponse object.
% (callback.__module__, view_name))
# 应用模板中间件(第四回合)(可选)
# 注意,这里应用模板中间件是无条件的,每个中间件都调用了,所以for语句中没有
# "if response: break"这样的语句。
if hasattr(response, 'render') and callable(response.render):
for middleware_method in self._template_response_middleware:
response = middleware_method(request, response)
response = response.render()
except http.Http404, e:
logger.warning('Not Found: %s', request.path,
extra={
'status_code': 404,
'request': request
})
if settings.DEBUG:
from django.views import debug
response = debug.technical_404_response(request, e)
else:
try:
callback, param_dict = resolver.resolve404()
response = callback(request, **param_dict)
except:
try:
response = self.handle_uncaught_exception(request,
resolver, sys.exc_info())
finally:
signals.got_request_exception.send(
sender=self.__class__, request=request)
except exceptions.PermissionDenied:
logger.warning(
'Forbidden (Permission denied): %s', request.path,
extra={
'status_code': 403,
'request': request
})
try:
callback, param_dict = resolver.resolve403()
response = callback(request, **param_dict)
except:
try:
response = self.handle_uncaught_exception(request,
resolver, sys.exc_info())
finally:
# 向系统发出处理异常的信号
signals.got_request_exception.send(
sender=self.__class__, request=request)
except SystemExit:
raise
except: # Handle everything else, including SuspiciousOperation,
# 向系统发出处理异常的信号
signals.got_request_exception.send(sender=self.__class__,
request=request)
response = self.handle_uncaught_exception(request, resolver,
sys.exc_info())
finally:
# 重置URLconf
urlresolvers.set_urlconf(None)
try:
# 应用响应中间件(第五回合),也是每个中间件都调用了
for middleware_method in self._response_middleware:
response = middleware_method(request, response)
# 对response对象的一些补丁处理
response = self.apply_response_fixes(request, response)
except:
# 向系统发出处理异常的信号
signals.got_request_exception.send(sender=self.__class__,
request=request)
# 最终会发出一个代表异常的响应
response = self.handle_uncaught_exception(request, resolver,
sys.exc_info())
return response