博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
How Django works?
阅读量:5268 次
发布时间:2019-06-14

本文共 7932 字,大约阅读时间需要 26 分钟。

Django是如何工作的?

概念

以线上版本中Django和Nginx、uwsgi搭配,这里首先要了解uWSGI、uwsgi、WSGI分别代表着什么,其中uWSGI实现了uwsgi、WSGI、HTTP协议的Web服务器,WSGI是通信协议,而uwsgi则是线路协议。

流程

当用户启动Nginx以后,Nginx会直接处理静态资源请求,动态资源请求则转发给uWSGI服务器。

调用get_wsgi_application创建WSGIHandler对象

Web应用启动以后,在settings.py中会调用该字段项WSGI_APPLICATION,这个字段项指向的是项目的wsgi.py文件,在这个文件中,调用了get_wsgi_application()创建了application,如下:

import osfrom django.core.wsgi import get_wsgi_applicationos.environ.setdefault("DJANGO_SETTINGS_MODULE", "Sparrow.settings")application = get_wsgi_application()

接下来再看get_wsgi_application的具体实现:

import djangofrom django.core.handlers.wsgi import WSGIHandlerdef 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)    return WSGIHandler()

里面调用了setup函数完成了一下动作:

  1. 初始化app配置和加载app模块;
  2. 加载model模块;
  3. 运行app配置的开始函数;

同时返回了WSGIHandler对象,这个对象继承自BaseHandler对象,在WSGIHandler初始化的时候还调用了BaseHandler对象的load_middleware()方法来加载中间件,也就是在settings.py中的MIDDLEWARE包含的所有中间件;注意,这里只有在初始化的时候调用,也就是只会加载一次即可。

加载中间件

BaseHandler中,分别用多个数组保存对应的中间件的回调函数,分别是:

  • _request_middleware
  • _view_middleware
  • _template_response_middleware
  • _response_middleware
  • _exception_middleware

在加载的时候,则会根据给定的类创建对应的中间件,判断中间件是否有对应的函数,有则将该函数加入到对应的数组中,如下:

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 = []  # 处理视图        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

构造WSGIRequest对象

WSGIHander初始化完成之后,然后它给调度程序发送一个信号request_started,并且将environ作为参数一块传递过去;同时还构造WSGIRequest请求对象,因为其继承的是HttpRequest,所以里面封装了HTTP协议的内容,比如meta、cookie、content_type等等;如下:

request_class = WSGIRequestrequest = self.request_class(environ)

处理response_middleware

接下来根据前面构造好的request作为参数通过get_response方法,在这个方法中会遍历_response_middleware数组中的每个方法并且获取到相应的响应信息,在这里对这些响应信息进行封装,设置一些cookie、headers等等;如下:

def __call__(self, environ, start_response):        set_script_prefix(get_script_name(environ))        signals.request_started.send(sender=self.__class__, environ=environ)  # 表明开始请求        request = self.request_class(environ)        response = self.get_response(request)  # 获取响应        response._handler_class = self.__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():            response_headers.append((str('Set-Cookie'), str(c.output(header=''))))        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

URLConf通过url.py文件找到请求的URL对应的视图函数

如果view不是一个函数,那么说明下面还有多个url,这种就是使用了include的情况,那么则会实例化RegexURLResolver对象,递归的往下找;相反,如果是一个函数,那么则会实例化RegexURLPattern对象,当url匹配到这个正则表达式的时候,就会进入到相应的函数。如下:

def url(regex, view, kwargs=None, name=None):    if isinstance(view, (list, tuple)):        # For include(...) processing.        urlconf_module, app_name, namespace = view        return RegexURLResolver(regex, urlconf_module, kwargs, app_name=app_name, namespace=namespace)    elif callable(view):        return RegexURLPattern(regex, view, kwargs, name)    else:        raise TypeError('view must be a callable or a list/tuple in the case of include().')

View Middlewares被访问,它同样可以对request做一些处理或者直接返回response

一旦知道了视图函数和相关的参数,处理器就会查看它的 _view_middleware 列表,并调用其中的方法。

调用View中的函数

在view中执行相关的逻辑,可以选择性的通过Models访问底层的数据。如果需要的话,Views可以创建一个额外的Context,Context被当做变量传给Template,比如将Models中获取的数据作为Context变量传递给模版。

模版渲染

模版根据可能传递过来的信息填充到指定的位置,开始进行渲染,渲染后的内容返回给View。

Response Middlewares处理Response

在Response生成之前,会执行Response Middlewares的逻辑。

返回Response给用户

当一个模版完成渲染,或者产生了其它合适的输出,View就会产生一 个 django.http.HttpResponse 实例,然后设置一些Headers、Cookies等等。

request_finished

一旦 middleware完成了最后环节,处理器将发送一个信号 request_finished,订阅这个信号的事件会清空并释放任何使用中的资源。

Exception

上面的情况并没有考虑到错误的情况,如果出错执行 exception middleware 相关逻辑,会有信号got_request_exception进行通知,如下:

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())

参考文章:

转载于:https://www.cnblogs.com/George1994/p/7297532.html

你可能感兴趣的文章
迭代器Iterator
查看>>
java易错题----静态方法的调用
查看>>
php建立MySQL数据表
查看>>
最简单的线程同步的例子
查看>>
JSP、Servlet乱码终极解决方案
查看>>
旅途上看的电影和观后感
查看>>
qt实现类似QQ伸缩窗口--鼠标事件应用
查看>>
Ztree异步树加载
查看>>
复杂问题的简单抽象:魔兽世界中的兔子们
查看>>
UVA 10529-Dumb Bones(概率dp)
查看>>
关于IE和火狐,谷歌,Safari对Html标签Object和Embed的支持问题
查看>>
MyEclipse DB Browser使用图文全攻略
查看>>
poj3320 Jessica's Reading Problem(尺取思路+STL)
查看>>
A - Vasya and Socks
查看>>
项目管理、设计开发、代码管理、bug管理工具介绍
查看>>
分布式计算开源框架Hadoop介绍
查看>>
安卓平台接口剖析
查看>>
linux文件编码查看与修改
查看>>
[Java] 系统环境变量配置
查看>>
坏的事情不都会带来坏的结果
查看>>