django源码分析——处理请求到wsgi及视图view
Posted thinheader
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了django源码分析——处理请求到wsgi及视图view相关的知识,希望对你有一定的参考价值。
本文环境python3.5.2,django1.10.x系列
根据前上一篇runserver的博文,已经分析了本地调试服务器的大致流程,现在我们来分析一下当runserver运行起来后,django框架是如何处理一个请求的,django框架是遵循了wsgi标准,所以django的项目可以和gunicorn等wsgi服务器配合使用,此处我们就主要分析一下django的wsgi流程分析。
在runserver函数中,有调用
def get_internal_wsgi_application():
"""
Loads and returns the WSGI application as configured by the user in
``settings.WSGI_APPLICATION``. With the default ``startproject`` layout,
this will be the ``application`` object in ``projectname/wsgi.py``.
This function, and the ``WSGI_APPLICATION`` setting itself, are only useful
for Django‘s internal server (runserver); external WSGI servers should just
be configured to point to the correct application object directly.
If settings.WSGI_APPLICATION is not set (is ``None``), we just return
whatever ``django.core.wsgi.get_wsgi_application`` returns.
"""
from django.conf import settings # 导入配置文件
app_path = getattr(settings, ‘WSGI_APPLICATION‘) # 获取配置文件中的wsgi运行的路径
if app_path is None: # 如果配置文件中没有则django/core/wsgi中的WSGIHandler
return get_wsgi_application()
try:
return import_string(app_path) # 如果配置文件中配置,则使用配置文件中的包
except ImportError as e:
msg = (
"WSGI application ‘%(app_path)s‘ could not be loaded; "
"Error importing module: ‘%(exception)s‘" % ({
‘app_path‘: app_path,
‘exception‘: e,
})
)
six.reraise(ImproperlyConfigured, ImproperlyConfigured(msg),
sys.exc_info()[2])
其中,函数get_wsgi_application()就是调用Django框架的wsgi来处理请求,
该函数位于django/core/wsgi.py中
def get_wsgi_application():
"""
The public interface to Django‘s WSGI support. Should return a WSGI
callable.
Allows us to avoid making django.core.handlers.WSGIHandler public API, in
case the internal WSGI implementation changes or moves in the future.
"""
django.setup(set_prefix=False) # 初始化django环境
return WSGIHandler()
其中django.setup()函数,会在后续文章中详细分析,Django环境的初始化,现在我们直接分析WSGIHandler类:
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super(WSGIHandler, self).__init__(*args, **kwargs)
self.load_middleware() # 加载中间件
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ) # 向接受通知的注册者发送通知
try:
request = self.request_class(environ) # 调用WSGIRequest实例化请求
except UnicodeDecodeError:
logger.warning(
‘Bad Request (UnicodeDecodeError)‘,
exc_info=sys.exc_info(),
extra={
‘status_code‘: 400,
}
)
response = http.HttpResponseBadRequest()
else:
response = self.get_response(request) # 调用处理方法处理request
response._handler_class = self.__class__ # 设置_handler_class 为当前处理的类
status = ‘%d %s‘ % (response.status_code, response.reason_phrase) # 相应结果的状态码和对应描述
response_headers = [(str(k), str(v)) for k, v in response.items()] # 获取响应的响应头部信息
for c in response.cookies.values(): # 获取响应的cookie信息
response_headers.append((str(‘Set-Cookie‘), str(c.output(header=‘‘)))) # 将cookie信息添加到头部信息中
start_response(force_str(status), response_headers) # 设置响应的响应头部信息
if getattr(response, ‘file_to_stream‘, None) is not None and environ.get(‘wsgi.file_wrapper‘): # 判断响应中是否有哦文件传输
response = environ[‘wsgi.file_wrapper‘](response.file_to_stream)
return response # 返回处理结果
首先调用BaseHandler中的load_middleware方法,Django中现在1.10系列版本中,所有的中间件对象都继承自MiddlewareMixin类:
class MiddlewareMixin(object):
def __init__(self, get_response=None): # 将获取结果处理函数传入
self.get_response = get_response
super(MiddlewareMixin, self).__init__()
def __call__(self, request):
response = None
if hasattr(self, ‘process_request‘): # 检查是否有process_request属性有就调用
response = self.process_request(request)
if not response: # response无结果则执行
response = self.get_response(request)
if hasattr(self, ‘process_response‘):
response = self.process_response(request, response) # 调用完成后处理
return response
此时,我们继续查看BaseHandler的分析:
class BaseHandler(object):
def __init__(self):
self._request_middleware = None # 初始化请求中间件,view中间件等值
self._view_middleware = None
self._template_response_middleware = None
self._response_middleware = None
self._exception_middleware = None
self._middleware_chain = None
def load_middleware(self):
"""
Populate middleware lists from settings.MIDDLEWARE (or the deprecated
MIDDLEWARE_CLASSES).
Must be called after the environment is fixed (see __call__ in subclasses).
"""
self._request_middleware = [] # 请求中间件
self._view_middleware = [] # view中间件
self._template_response_middleware = [] # 模板中间件
self._response_middleware = [] # 响应中间件
self._exception_middleware = [] # 错误处理中间件
if settings.MIDDLEWARE is None: # 如果配置文件中没有找到中间件配置
warnings.warn(
"Old-style middleware using settings.MIDDLEWARE_CLASSES is "
"deprecated. Update your middleware and use settings.MIDDLEWARE "
"instead.", RemovedInDjango20Warning
) # 提示旧的中间件写法,需要更新到新的中间件写法
handler = convert_exception_to_response(self._legacy_get_response) # 处理中间件,由于该处理方法只是兼容旧方法,所以不在此分析
for middleware_path in settings.MIDDLEWARE_CLASSES:
mw_class = import_string(middleware_path)
try:
mw_instance = mw_class()
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if six.text_type(exc):
logger.debug(‘MiddlewareNotUsed(%r): %s‘, middleware_path, exc)
else:
logger.debug(‘MiddlewareNotUsed: %r‘, middleware_path)
continue
if hasattr(mw_instance, ‘process_request‘):
self._request_middleware.append(mw_instance.process_request)
if hasattr(mw_instance, ‘process_view‘):
self._view_middleware.append(mw_instance.process_view)
if hasattr(mw_instance, ‘process_template_response‘):
self._template_response_middleware.insert(0, mw_instance.process_template_response)
if hasattr(mw_instance, ‘process_response‘):
self._response_middleware.insert(0, mw_instance.process_response)
if hasattr(mw_instance, ‘process_exception‘):
self._exception_middleware.insert(0, mw_instance.process_exception)
else: # 新的中间件的写法
handler = convert_exception_to_response(self._get_response) # 将处理响应包装出错处理
for middleware_path in reversed(settings.MIDDLEWARE): # 获取中间件的包路径
middleware = import_string(middleware_path) # 导入中间件包类
try:
mw_instance = middleware(handler) # 初始化该类
except MiddlewareNotUsed as exc:
if settings.DEBUG:
if six.text_type(exc):
logger.debug(‘MiddlewareNotUsed(%r): %s‘, middleware_path, exc)
else:
logger.debug(‘MiddlewareNotUsed: %r‘, middleware_path)
continue
if mw_instance is None:
raise ImproperlyConfigured(
‘Middleware factory %s returned None.‘ % middleware_path
)
if hasattr(mw_instance, ‘process_view‘): # 如果该中间件实例有该方法则添加到列表中
self._view_middleware.insert(0, mw_instance.process_view)
if hasattr(mw_instance, ‘process_template_response‘):
self._template_response_middleware.append(mw_instance.process_template_response)
if hasattr(mw_instance, ‘process_exception‘):
self._exception_middleware.append(mw_instance.process_exception)
handler = convert_exception_to_response(mw_instance) # 对该实例运行出错的情况进行处理
# We only assign to this when initialization is complete as it is used
# as a flag for initialization being complete.
self._middleware_chain = handler # 将中间件最后一个进行出错处理的对象传入
def make_view_atomic(self, view):
non_atomic_requests = getattr(view, ‘_non_atomic_requests‘, set()) # 获取处理view是否有不是使用事务处理属性
for db in connections.all():
if db.settings_dict[‘ATOMIC_REQUESTS‘] and db.alias not in non_atomic_requests: # 如果数据库配置每个请求一个事务并且该数据库不再不使用事务请求列表中
view = transaction.atomic(using=db.alias)(view) # 处理事务就是一个事务处理
return view
def get_exception_response(self, request, resolver, status_code, exception):
return get_exception_response(request, resolver, status_code, exception, self.__class__)
def get_response(self, request):
"""Return an HttpResponse object for the given HttpRequest."""
# Setup default url resolver for this thread
set_urlconf(settings.ROOT_URLCONF) # 设置url配置
response = self._middleware_chain(request) # 调用107行的handler处理,该方法会调用_get_response
# This block is only needed for legacy MIDDLEWARE_CLASSES; if
# MIDDLEWARE is used, self._response_middleware will be empty.
try:
# Apply response middleware, regardless of the response
for middleware_method in self._response_middleware: # 检查response中间件方法
response = middleware_method(request, response) # 调用并处理
# Complain if the response middleware returned None (a common error).
if response is None:
raise ValueError(
"%s.process_response didn‘t return an "
"HttpResponse object. It returned None instead."
% (middleware_method.__self__.__class__.__name__))
except Exception: # Any exception should be gathered and handled
signals.got_request_exception.send(sender=self.__class__, request=request)
response = self.handle_uncaught_exception(request, get_resolver(get_urlconf()), sys.exc_info())
response._closable_objects.append(request)
# If the exception handler returns a TemplateResponse that has not
# been rendered, force it to be rendered.
if not getattr(response, ‘is_rendered‘, True) and callable(getattr(response, ‘render‘, None)): # 获取是否是渲染的并且渲染方法能够调用
response = response.render() # 渲染结果
if response.status_code == 404:
logger.warning(
‘Not Found: %s‘, request.path,
extra={‘status_code‘: 404, ‘request‘: request},
)
return response # 返回处理结果
def _get_response(self, request):
"""
Resolve and call the view, then apply view, exception, and
template_response middleware. This method is everything that happens
inside the request/response middleware.
"""
response = None # 设置返回值为空
if hasattr(request, ‘urlconf‘): # 检查request是否有urlconf属性
urlconf = request.urlconf
set_urlconf(urlconf) # 设置urlconf,由于是线程安全,所以会设置
resolver = get_resolver(urlconf) # 获取url解析处理函数
else:
resolver = get_resolver() # 如果没有改属性就获取默认settings中的url
resolver_match = resolver.resolve(request.path_info) # 根据传入的请求路径解析匹配的处理函数
callback, callback_args, callback_kwargs = resolver_match # 获取配置的处理函数
request.resolver_match = resolver_match
# Apply view middleware
for middleware_method in self._view_middleware:
response = middleware_method(request, callback, callback_args, callback_kwargs) # 检查是否视图函数中的中间件处理函数
if response:
break
if response is None:
wrapped_callback = self.make_view_atomic(callback) # 检查是否是一个请求就是一个事务
try:
response = wrapped_callback(request, *callback_args, **callback_kwargs) # 调用处理回调函数处理请求
except Exception as e:
response = self.process_exception_by_middleware(e, request)
# Complain if the view returned None (a common error).
if response is None:
if isinstance(callback, types.FunctionType): # FBV
view_name = callback.__name__
else: # CBV
view_name = callback.__class__.__name__ + ‘.__call__‘
raise ValueError(
"The view %s.%s didn‘t return an HttpResponse object. It "
"returned None instead." % (callback.__module__, view_name)
)
# If the response supports deferred rendering, apply template
# response middleware and then render the response
elif hasattr(response, ‘render‘) and callable(response.render): # 检查响应是否有render
for middleware_method in self._template_response_middleware: # 如果有调用模板中间函数处理
response = middleware_method(request, response)
# Complain if the template response middleware returned None (a common error).
if response is None:
raise ValueError(
"%s.process_template_response didn‘t return an "
"HttpResponse object. It returned None instead."
% (middleware_method.__self__.__class__.__name__)
)
try:
response = response.render() # 渲染返回结果
except Exception as e:
response = self.process_exception_by_middleware(e, request) # 调用中间件错误函数处理
return response # 返回响应
def process_exception_by_middleware(self, exception, request):
"""
Pass the exception to the exception middleware. If no middleware
return a response for this exception, raise it.
"""
for middleware_method in self._exception_middleware:
response = middleware_method(request, exception)
if response:
return response
raise
def handle_uncaught_exception(self, request, resolver, exc_info):
"""Allow subclasses to override uncaught exception handling."""
return handle_uncaught_exception(request, resolver, exc_info)
def _legacy_get_response(self, request):
"""
Apply process_request() middleware and call the main _get_response(),
if needed. Used only for legacy MIDDLEWARE_CLASSES.
"""
response = None
# Apply request middleware
for middleware_method in self._request_middleware:
response = middleware_method(request)
if response: