zoukankan      html  css  js  c++  java
  • Django运行方式及处理流程总结

    学了django有一段时间了,也没深入了解过它内部的实现,正好看到一篇介绍django运行原理的,有图有代码,深度好文,值得收藏。
                             -- xxmcf 2015.09.28 22:29
    原文链接: 

    前在网上看过一些介绍Django处理请求的流程和Django源码结构的文章,觉得了解一下这些内容对开发Django项目还是很有帮助的。所以,我按照自己的逻辑总结了一下Django项目的运行方式和对Request的基本处理流程。


    一、Django的运行方式

    运行Django项目的方法很多,这里主要介绍一下常用的方法。一种是在开发和调试中经常用到runserver方法,使用Django自己的web server;另外一种就是使用fastcgi,uWSGIt等协议运行Django项目,这里以uWSGIt为例。

    1、runserver方法

    runserver方法是调试Django时经常用到的运行方式,它使用Django自带的WSGI Server运行,主要在测试和开发中使用,使用方法如下:

     

    [python] view plain copy
    1. Usage: manage.py runserver [options] [optional port number, or ipaddr:port]  
    2. # python manager.py runserver    # default port is 8000  
    3. # python manager.py runserver 8080  
    4. # python manager.py runserver 127.0.0.1:9090  

    看一下manager.py的源码,你会发现上面的命令其实是通过Django的execute_from_command_line方法执行了内部实现的runserver命令,那么现在看一下runserver具体做了什么。。

        1). 解析参数,并通过django.core.servers.basehttp.get_internal_wsgi_application方法获取wsgi handler;

        2). 根据ip_address和port生成一个WSGIServer对象,接受用户请求

     

    [python] view plain copy
    1. def get_internal_wsgi_application():  
    2.     """ 
    3.     Loads and returns the WSGI application as configured by the user in 
    4.     ``settings.WSGI_APPLICATION``. With the default ``startproject`` layout, 
    5.     this will be the ``application`` object in ``projectname/wsgi.py``. 
    6.   
    7.     This function, and the ``WSGI_APPLICATION`` setting itself, are only useful 
    8.     for Django's internal servers (runserver, runfcgi); external WSGI servers 
    9.     should just be configured to point to the correct application object 
    10.     directly. 
    11.   
    12.     If settings.WSGI_APPLICATION is not set (is ``None``), we just return 
    13.     whatever ``django.core.wsgi.get_wsgi_application`` returns. 
    14.   
    15.     """  
    16.     from django.conf import settings  
    17.     app_path = getattr(settings, 'WSGI_APPLICATION')  
    18.     if app_path is None:  
    19.         return get_wsgi_application()  
    20.    
    21.     return import_by_path(  
    22.         app_path,  
    23.         error_prefix="WSGI application '%s' could not be loaded; " % app_path  
    24.     )  

    通过上面的代码我们可以知道,Django会先根据settings中的WSGI_APPLICATION来获取handler;在创建project的时候,Django会默认创建一个wsgi.py文件,而settings中的WSGI_APPLICATION配置也会默认指向这个文件。看一下这个wsgi.py文件,其实它也和上面的逻辑一样,最终调用get_wsgi_application实现。


    2、uWSGI方法

    uWSGI+Nginx的方法是现在最常见的在生产环境中运行Django的方法,本人的博客也是使用这种方法运行,要了解这种方法,首先要了解一下WSGI和uWSGI协议。

    WSGI,全称Web Server Gateway Interface,或者Python Web Server Gateway Interface,是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口,基于现存的CGI标准而设计的。WSGI其实就是一个网关(Gateway),其作用就是在协议之间进行转换。(PS: 这里只对WSGI做简单介绍,想要了解更多的内容可自行搜索)

    uWSGI是一个Web服务器,它实现了WSGI协议、uwsgi、http等协议。注意uwsgi是一种通信协议,而uWSGI是实现uwsgi协议和WSGI协议的Web服务器。uWSGI具有超快的性能、低内存占用和多app管理等优点。以我的博客为例,uWSGI的xml配置如下:

    uwsgi>  

    •     <!-- 端口 -->  
    •     <socket>:7600</socket>  
    •     <stats>:40000</stats>  
    •     <!-- 系统环境变量 -->  
    •     <env>DJANGO_SETTINGS_MODULE=geek_blog.settings</env>  
    •     <!-- 指定的python WSGI模块 -->  
    •     <module>django.core.handlers.wsgi:WSGIHandler()</module>  
    •     <processes>6</processes>  
    •     <master />  
    •     <master-as-root />  
    •     <!-- 超时设置 -->  
    •     <harakiri>60</harakiri>  
    •     <harakiri-verbose/>  
    •     <daemonize>/var/app/log/blog/uwsgi.log</daemonize>  
    •     <!-- socket的监听队列大小 -->  
    •     <listen>32768</listen>  
    •     <!-- 内部超时时间 -->  
    •     <socket-timeout>60</socket-timeout>  
    • </uwsgi>  


    • uwsgi --pidfile=/var/run/geek-blog.pid -x uwsgi.xml --uid blog --gid nogroup  
    uWSGI和Nginx一起使用的配置方法就不在这里说明了,网上教程很多,需要的可以自行搜索。


    二、HTTP请求处理流程

    Django和其他Web框架一样,HTTP的处理流程基本类似:接受request,返回response内容。Django的具体处理流程大致如下图所示:

    1、加载project settings

    创建WSGIServer之前会执行下面的引用:

     

    [python] view plain copy
    1. from django.conf import settings  


    上面引用在执行时,会读取os.environ中的DJANGO_SETTINGS_MODULE配置,加载项目配置文件,生成settings对象。所以,在manager.py文件中你可以看到,在获取WSGIServer之前,会先将project的settings路径加到os路径中。

    2、创建WSGIServer

     

     

    [python] view plain copy
    1. def run(addr, port, wsgi_handler, ipv6=False, threading=False):  
    2.     server_address = (addr, port)  
    3.     if threading:  
    4.         httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})  
    5.     else:  
    6.         httpd_cls = WSGIServer  
    7.     httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)  
    8.     # Sets the callable application as the WSGI application that will receive requests  
    9.     httpd.set_app(wsgi_handler)  
    10.     httpd.serve_forever()  


    其中,WSGIServer继承自wsgiref.simple_server.WSGIServer,而WSGIRequestHandler继承自wsgiref.simple_server.WSGIRequestHandler,wsgiref是Python标准库给出的WSGI的参考实现。其源码可自行到wsgiref参看,这里不再细说。

    3、处理Request

    第二步中说到的application,在Django中一般是django.core.handlers.wsgi.WSGIHandler对象,WSGIHandler继承自django.core.handlers.base.BaseHandler,这个是Django处理request的核心逻辑,它会创建一个WSGIRequest实例,而WSGIRequest是从http.HttpRequest继承而来

    4、返回Response

    上面提到的BaseHandler中有个get_response方法,该方法会先加载Django项目的ROOT_URLCONF,然后根据url规则找到对应的view方法(类),view逻辑会根据request实例生成并返回具体的response。

    在Django返回结果之后,第二步中提到wsgiref.handlers.BaseHandler.run方法会调用finish_response结束请求,并将内容返回给用户。

    三、Django处理Request的详细流程

    Django流程图1

    Django流程图2

        1. 用户通过浏览器请求一个页面

        2. 请求到达Request Middlewares,中间件对request做一些预处理或者直接response请求

        3. URLConf通过urls.py文件和请求的URL找到相应的View

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

        5. 调用View中的函数

        6. View中的方法可以选择性的通过Models访问底层的数据

        7. 所有的Model-to-DB的交互都是通过manager完成的

        8. 如果需要,Views可以使用一个特殊的Context

        9. Context被传给Template用来生成页面

        a. Template使用Filters和Tags去渲染输出

        b. 输出被返回到View

        c. HTTPResponse被发送到Response Middlewares

        d. 任何Response Middlewares都可以丰富response或者返回一个完全不同的response

        e. Response返回到浏览器,呈现给用户

    1、Middleware(中间件)

    Middleware是在Django BaseHandler的load_middleware方法执行时加载的,加载之后会建立四个列表作为处理器的实例变量:

        _request_middleware:process_request方法的列表

        _view_middleware:process_view方法的列表

        _response_middleware:process_response方法的列表

        _exception_middleware:process_exception方法的列表

     

    [python] view plain copy
    1. MIDDLEWARE_CLASSES = (  
    2.     'django.middleware.cache.UpdateCacheMiddleware',  
    3.     'django.middleware.common.CommonMiddleware',  
    4.     'django.middleware.cache.FetchFromCacheMiddleware',  
    5.     'django.contrib.sessions.middleware.SessionMiddleware',  
    6.     'django.middleware.csrf.CsrfViewMiddleware',  
    7.     'django.contrib.auth.middleware.AuthenticationMiddleware',  
    8.     'django.contrib.messages.middleware.MessageMiddleware',  
    9.     'django.middleware.locale.LocaleMiddleware',  
    10.     'geek_blog.middlewares.MobileDetectionMiddleware',    # 自定义的Middleware  
    11. )  

    Django项目的安装并不强制要求任何中间件,如果你愿意,MIDDLEWARE_CLASSES可以为空。中间件出现的顺序非常重要:在request和view的处理阶段,Django按照MIDDLEWARE_CLASSES中出现的顺序来应用中间件,而在response和exception异常处理阶段,Django则按逆序来调用它们。也就是说,Django将MIDDLEWARE_CLASSES视为view函数外层的顺序包装子:在request阶段按顺序从上到下穿过,而在response则反过来。以下两张图可以更好地帮助你理解:

    Django Middleware流程1

    Django Middleware流程图2

    2、URLConf(URL映射)

    第一个匹配的view。

    DjangoBook了解。

    3、Template(模板)


    uWSGI Web服务器介绍

    wsgiref源码分析

    用Python写一个简单的Web框架

    Django 结构及处理流程分析

    PS: 以上代码和内容都是基于Django 1.6.5版本,其他版本可能与其不同,请参考阅读。

    Over!

    人生当自勉,学习需坚持。从这一刻开始,我依旧是我,只是心境再不同。不论今后的路如何,我都会在心底默默鼓励自己,坚持不懈,等待那一场破茧的美丽。
  • 相关阅读:
    C字符串和C++字符串
    Linux的用户态和内核态
    知乎问答:如何理解“In UNIX, everything is a file”?
    科普:并行计算、分布式计算、集群计算和云计算
    个人使用VIM的一些总结
    C语言回调函数学习
    Python的函数参数传递:传值?引用?
    ECMAScript 函数函数概述
    ECMAScript 函数arguments 对象
    ECMAScript 语句with 语句
  • 原文地址:https://www.cnblogs.com/jiangqiuju/p/8125667.html
Copyright © 2011-2022 走看看