亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

分析Python的Django框架的運(yùn)行方式及處理流程

 更新時(shí)間:2015年04月08日 16:51:32   作者:吳文苑  
這篇文章主要介紹了分析Python的Django框架的運(yùn)行方式及處理流程,本文對(duì)于Django框架的機(jī)制總結(jié)得非常之直觀精煉,極力推薦!需要的朋友可以參考下

之前在網(wǎng)上看過(guò)一些介紹Django處理請(qǐng)求的流程和Django源碼結(jié)構(gòu)的文章,覺(jué)得了解一下這些內(nèi)容對(duì)開(kāi)發(fā)Django項(xiàng)目還是很有幫助的。所以,我按照自己的邏輯總結(jié)了一下Django項(xiàng)目的運(yùn)行方式和對(duì)Request的基本處理流程。


一、Django的運(yùn)行方式

運(yùn)行Django項(xiàng)目的方法很多,這里主要介紹一下常用的方法。一種是在開(kāi)發(fā)和調(diào)試中經(jīng)常用到runserver方法,使用Django自己的web server;另外一種就是使用fastcgi,uWSGIt等協(xié)議運(yùn)行Django項(xiàng)目,這里以u(píng)WSGIt為例。

1、runserver方法

runserver方法是調(diào)試Django時(shí)經(jīng)常用到的運(yùn)行方式,它使用Django自帶的WSGI Server運(yùn)行,主要在測(cè)試和開(kāi)發(fā)中使用,使用方法如下:

Usage: manage.py runserver [options] [optional port number, or ipaddr:port]
# python manager.py runserver  # default port is 8000
# python manager.py runserver 8080
# python manager.py runserver 127.0.0.1:9090

看一下manager.py的源碼,你會(huì)發(fā)現(xiàn)上面的命令其實(shí)是通過(guò)Django的execute_from_command_line方法執(zhí)行了內(nèi)部實(shí)現(xiàn)的runserver命令,那么現(xiàn)在看一下runserver具體做了什么。。

看了源碼之后,可以發(fā)現(xiàn)runserver命令主要做了兩件事情:

    1). 解析參數(shù),并通過(guò)django.core.servers.basehttp.get_internal_wsgi_application方法獲取wsgi handler;

    2). 根據(jù)ip_address和port生成一個(gè)WSGIServer對(duì)象,接受用戶請(qǐng)求

get_internal_wsgi_application的源碼如下:
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 servers (runserver, runfcgi); 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')
  if app_path is None:
    return get_wsgi_application()
 
  return import_by_path(
    app_path,
    error_prefix="WSGI application '%s' could not be loaded; " % app_path
  )

通過(guò)上面的代碼我們可以知道,Django會(huì)先根據(jù)settings中的WSGI_APPLICATION來(lái)獲取handler;在創(chuàng)建project的時(shí)候,Django會(huì)默認(rèn)創(chuàng)建一個(gè)wsgi.py文件,而settings中的WSGI_APPLICATION配置也會(huì)默認(rèn)指向這個(gè)文件??匆幌逻@個(gè)wsgi.py文件,其實(shí)它也和上面的邏輯一樣,最終調(diào)用get_wsgi_application實(shí)現(xiàn)。

2、uWSGI方法

uWSGI+Nginx的方法是現(xiàn)在最常見(jiàn)的在生產(chǎn)環(huán)境中運(yùn)行Django的方法,本人的博客也是使用這種方法運(yùn)行,要了解這種方法,首先要了解一下WSGI和uWSGI協(xié)議。

WSGI,全稱Web Server Gateway Interface,或者Python Web Server Gateway Interface,是為Python語(yǔ)言定義的Web服務(wù)器和Web應(yīng)用程序或框架之間的一種簡(jiǎn)單而通用的接口,基于現(xiàn)存的CGI標(biāo)準(zhǔn)而設(shè)計(jì)的。WSGI其實(shí)就是一個(gè)網(wǎng)關(guān)(Gateway),其作用就是在協(xié)議之間進(jìn)行轉(zhuǎn)換。(PS: 這里只對(duì)WSGI做簡(jiǎn)單介紹,想要了解更多的內(nèi)容可自行搜索)

uWSGI是一個(gè)Web服務(wù)器,它實(shí)現(xiàn)了WSGI協(xié)議、uwsgi、http等協(xié)議。注意uwsgi是一種通信協(xié)議,而uWSGI是實(shí)現(xiàn)uwsgi協(xié)議和WSGI協(xié)議的Web服務(wù)器。uWSGI具有超快的性能、低內(nèi)存占用和多app管理等優(yōu)點(diǎn)。以我的博客為例,uWSGI的xml配置如下:

<uwsgi>
  <!-- 端口 -->
  <socket>:7600</socket>
  <stats>:40000</stats>
  <!-- 系統(tǒng)環(huán)境變量 -->
  <env>DJANGO_SETTINGS_MODULE=geek_blog.settings</env>
  <!-- 指定的python WSGI模塊 -->
  <module>django.core.handlers.wsgi:WSGIHandler()</module>
  <processes>6</processes>
  <master />
  <master-as-root />
  <!-- 超時(shí)設(shè)置 -->
  <harakiri>60</harakiri>
  <harakiri-verbose/>
  <daemonize>/var/app/log/blog/uwsgi.log</daemonize>
  <!-- socket的監(jiān)聽(tīng)隊(duì)列大小 -->
  <listen>32768</listen>
  <!-- 內(nèi)部超時(shí)時(shí)間 -->
  <socket-timeout>60</socket-timeout>
</uwsgi>

以上就是uWSGI xml配置的寫法,也可以使用ini的方式。安裝uWSGI和運(yùn)行的命令如下:

sudo pip install uwsgi
uwsgi --pidfile=/var/run/geek-blog.pid -x uwsgi.xml --uid blog --gid nogroup

uWSGI和Nginx一起使用的配置方法就不在這里說(shuō)明了,網(wǎng)上教程很多,需要的可以自行搜索。


二、HTTP請(qǐng)求處理流程

Django和其他Web框架一樣,HTTP的處理流程基本類似:接受request,返回response內(nèi)容。Django的具體處理流程大致如下圖所示:

1、加載project settings

在通過(guò)django-admin.py創(chuàng)建project的時(shí)候,Django會(huì)自動(dòng)生成默認(rèn)的settings文件和manager.py等文件,在創(chuàng)建WSGIServer之前會(huì)執(zhí)行下面的引用:
from django.conf import settings

上面引用在執(zhí)行時(shí),會(huì)讀取os.environ中的DJANGO_SETTINGS_MODULE配置,加載項(xiàng)目配置文件,生成settings對(duì)象。所以,在manager.py文件中你可以看到,在獲取WSGIServer之前,會(huì)先將project的settings路徑加到os路徑中。

2、創(chuàng)建WSGIServer

不管是使用runserver還是uWSGI運(yùn)行Django項(xiàng)目,在啟動(dòng)時(shí)都會(huì)調(diào)用django.core.servers.basehttp中的run()方法,創(chuàng)建一個(gè)django.core.servers.basehttp.WSGIServer類的實(shí)例,之后調(diào)用其serve_forever()方法啟動(dòng)HTTP服務(wù)。run方法的源碼如下:

def run(addr, port, wsgi_handler, ipv6=False, threading=False):
  server_address = (addr, port)
  if threading:
    httpd_cls = type(str('WSGIServer'), (socketserver.ThreadingMixIn, WSGIServer), {})
  else:
    httpd_cls = WSGIServer
  httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
  # Sets the callable application as the WSGI application that will receive requests
  httpd.set_app(wsgi_handler)
  httpd.serve_forever()

如上,我們可以看到:在創(chuàng)建WSGIServer實(shí)例的時(shí)候會(huì)指定HTTP請(qǐng)求的Handler,上述代碼使用WSGIRequestHandler。當(dāng)用戶的HTTP請(qǐng)求到達(dá)服務(wù)器時(shí),WSGIServer會(huì)創(chuàng)建WSGIRequestHandler實(shí)例,使用其handler方法來(lái)處理HTTP請(qǐng)求(其實(shí)最終是調(diào)用wsgiref.handlers.BaseHandler中的run方法處理)。WSGIServer通過(guò)set_app方法設(shè)置一個(gè)可調(diào)用(callable)的對(duì)象作為application,上面提到的handler方法最終會(huì)調(diào)用設(shè)置的application處理request,并返回response。

其中,WSGIServer繼承自wsgiref.simple_server.WSGIServer,而WSGIRequestHandler繼承自wsgiref.simple_server.WSGIRequestHandler,wsgiref是Python標(biāo)準(zhǔn)庫(kù)給出的WSGI的參考實(shí)現(xiàn)。其源碼可自行到wsgiref參看,這里不再細(xì)說(shuō)。

3、處理Request

第二步中說(shuō)到的application,在Django中一般是django.core.handlers.wsgi.WSGIHandler對(duì)象,WSGIHandler繼承自django.core.handlers.base.BaseHandler,這個(gè)是Django處理request的核心邏輯,它會(huì)創(chuàng)建一個(gè)WSGIRequest實(shí)例,而WSGIRequest是從http.HttpRequest繼承而來(lái)

4、返回Response

上面提到的BaseHandler中有個(gè)get_response方法,該方法會(huì)先加載Django項(xiàng)目的ROOT_URLCONF,然后根據(jù)url規(guī)則找到對(duì)應(yīng)的view方法(類),view邏輯會(huì)根據(jù)request實(shí)例生成并返回具體的response。

在Django返回結(jié)果之后,第二步中提到wsgiref.handlers.BaseHandler.run方法會(huì)調(diào)用finish_response結(jié)束請(qǐng)求,并將內(nèi)容返回給用戶。


三、Django處理Request的詳細(xì)流程

上述的第三步和第四步邏輯只是大致說(shuō)了一下處理過(guò)程,Django在處理request的時(shí)候其實(shí)做了很多事情,下面我們?cè)敿?xì)的過(guò)一下。首先給大家分享兩個(gè)網(wǎng)上看到的Django流程圖:

201548164301191.png (467×525)

Django流程圖1

201548164415899.png (531×699)

Django流程圖2
上面的兩張流程圖可以大致描述Django處理request的流程,按照流程圖2的標(biāo)注,可以分為以下幾個(gè)步驟:

    1. 用戶通過(guò)瀏覽器請(qǐng)求一個(gè)頁(yè)面

    2. 請(qǐng)求到達(dá)Request Middlewares,中間件對(duì)request做一些預(yù)處理或者直接response請(qǐng)求

    3. URLConf通過(guò)urls.py文件和請(qǐng)求的URL找到相應(yīng)的View

    4. View Middlewares被訪問(wèn),它同樣可以對(duì)request做一些處理或者直接返回response

    5. 調(diào)用View中的函數(shù)

    6. View中的方法可以選擇性的通過(guò)Models訪問(wèn)底層的數(shù)據(jù)

    7. 所有的Model-to-DB的交互都是通過(guò)manager完成的

    8. 如果需要,Views可以使用一個(gè)特殊的Context

    9. Context被傳給Template用來(lái)生成頁(yè)面

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

    b. 輸出被返回到View

    c. HTTPResponse被發(fā)送到Response Middlewares

    d. 任何Response Middlewares都可以豐富response或者返回一個(gè)完全不同的response

    e. Response返回到瀏覽器,呈現(xiàn)給用戶

上述流程中最主要的幾個(gè)部分分別是:Middleware(中間件,包括request, view, exception, response),URLConf(url映射關(guān)系),Template(模板系統(tǒng)),下面一一介紹一下。

1、Middleware(中間件)

Middleware并不是Django所獨(dú)有的東西,在其他的Web框架中也有這種概念。在Django中,Middleware可以滲入處理流程的四個(gè)階段:request,view,response和exception,相應(yīng)的,在每個(gè)Middleware類中都有rocess_request,process_view, process_response 和 process_exception這四個(gè)方法。你可以定義其中任意一個(gè)活多個(gè)方法,這取決于你希望該Middleware作用于哪個(gè)處理階段。每個(gè)方法都可以直接返回response對(duì)象。

Middleware是在Django BaseHandler的load_middleware方法執(zhí)行時(shí)加載的,加載之后會(huì)建立四個(gè)列表作為處理器的實(shí)例變量:

  1.     _request_middleware:process_request方法的列表
  2.     _view_middleware:process_view方法的列表
  3.     _response_middleware:process_response方法的列表
  4.     _exception_middleware:process_exception方法的列表

Django的中間件是在其配置文件(settings.py)的MIDDLEWARE_CLASSES元組中定義的。在MIDDLEWARE_CLASSES中,中間件組件用字符串表示:指向中間件類名的完整Python路徑。例如GeekBlog項(xiàng)目的配置:

MIDDLEWARE_CLASSES = (
  'django.middleware.cache.UpdateCacheMiddleware',
  'django.middleware.common.CommonMiddleware',
  'django.middleware.cache.FetchFromCacheMiddleware',
  'django.contrib.sessions.middleware.SessionMiddleware',
  'django.middleware.csrf.CsrfViewMiddleware',
  'django.contrib.auth.middleware.AuthenticationMiddleware',
  'django.contrib.messages.middleware.MessageMiddleware',
  'django.middleware.locale.LocaleMiddleware',
  'geek_blog.middlewares.MobileDetectionMiddleware',  # 自定義的Middleware
)

Django項(xiàng)目的安裝并不強(qiáng)制要求任何中間件,如果你愿意,MIDDLEWARE_CLASSES可以為空。中間件出現(xiàn)的順序非常重要:在request和view的處理階段,Django按照MIDDLEWARE_CLASSES中出現(xiàn)的順序來(lái)應(yīng)用中間件,而在response和exception異常處理階段,Django則按逆序來(lái)調(diào)用它們。也就是說(shuō),Django將MIDDLEWARE_CLASSES視為view函數(shù)外層的順序包裝子:在request階段按順序從上到下穿過(guò),而在response則反過(guò)來(lái)。以下兩張圖可以更好地幫助你理解:

201548164517915.png (502×417)

Django Middleware流程1

201548164601481.png (899×226)

Django Middleware流程圖2
2、URLConf(URL映射)

如果處理request的中間件都沒(méi)有直接返回response,那么Django會(huì)去解析用戶請(qǐng)求的URL。URLconf就是Django所支撐網(wǎng)站的目錄。它的本質(zhì)是URL模式以及要為該URL模式調(diào)用的視圖函數(shù)之間的映射表。通過(guò)這種方式可以告訴Django,對(duì)于這個(gè)URL調(diào)用這段代碼,對(duì)于那個(gè)URL調(diào)用那段代碼。具體的,在Django項(xiàng)目的配置文件中有ROOT_URLCONF常量,這個(gè)常量加上根目錄"/",作為參數(shù)來(lái)創(chuàng)建django.core.urlresolvers.RegexURLResolver的實(shí)例,然后通過(guò)它的resolve方法解析用戶請(qǐng)求的URL,找到第一個(gè)匹配的view。

其他有關(guān)URLConf的內(nèi)容,這里不再具體介紹,大家可以看DjangoBook了解。

3、Template(模板)

大部分web框架都有自己的Template(模板)系統(tǒng),Django也是。但是,Django模板不同于Mako模板和jinja2模板,在Django模板不能直接寫Python代碼,只能通過(guò)額外的定義filter和template tag實(shí)現(xiàn)。由于本文主要介紹Django流程,模板內(nèi)容就不過(guò)多介紹。


PS: 以上代碼和內(nèi)容都是基于Django 1.6.5版本,其他版本可能與其不同,請(qǐng)參考閱讀。


Over!

相關(guān)文章

最新評(píng)論