分析Python的Django架構的運行方式及處理流程

來源:互聯網
上載者:User
之前在網上看過一些介紹Django處理請求的流程和Django源碼結構的文章,覺得瞭解一下這些內容對開發Django項目還是很有協助的。所以,我按照自己的邏輯總結了一下Django項目的運行方式和對Request的基本處理流程。


一、Django的運行方式

運行Django項目的方法很多,這裡主要介紹一下常用的方法。一種是在開發和調試中經常用到runserver方法,使用Django自己的web server;另外一種就是使用fastcgi,uWSGIt等協議運行Django項目,這裡以uWSGIt為例。

1、runserver方法

runserver方法是調試Django時經常用到的運行方式,它使用Django內建的WSGI Server運行,主要在測試和開發中使用,使用方法如下:

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的源碼,你會發現上面的命令其實是通過Django的execute_from_command_line方法執行了內部實現的runserver命令,那麼現在看一下runserver具體做了什麼。。

看了源碼之後,可以發現runserver命令主要做了兩件事情:

1). 解析參數,並通過django.core.servers.basehttp.get_internal_wsgi_application方法擷取wsgi handler;

2). 根據ip_address和port產生一個WSGIServer對象,接受使用者請求

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  )

通過上面的代碼我們可以知道,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配置如下:

    :7600  :40000    DJANGO_SETTINGS_MODULE=geek_blog.settings    django.core.handlers.wsgi:WSGIHandler()  6        60    /var/app/log/blog/uwsgi.log    32768    60

以上就是uWSGI xml配置的寫法,也可以使用ini的方式。安裝uWSGI和啟動並執行命令如下:

sudo pip install uwsgiuwsgi --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

在通過django-admin.py建立project的時候,Django會自動產生預設的settings檔案和manager.py等檔案,在建立WSGIServer之前會執行下面的引用:
from django.conf import settings

上面引用在執行時,會讀取os.environ中的DJANGO_SETTINGS_MODULE配置,附加元件目設定檔,產生settings對象。所以,在manager.py檔案中你可以看到,在擷取WSGIServer之前,會先將project的settings路徑加到os路徑中。

2、建立WSGIServer

不管是使用runserver還是uWSGI運行Django項目,在啟動時都會調用django.core.servers.basehttp中的run()方法,建立一個django.core.servers.basehttp.WSGIServer類的執行個體,之後調用其serve_forever()方法啟動HTTP服務。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()

如上,我們可以看到:在建立WSGIServer執行個體的時候會指定HTTP請求的Handler,上述代碼使用WSGIRequestHandler。當使用者的HTTP請求到達伺服器時,WSGIServer會建立WSGIRequestHandler執行個體,使用其handler方法來處理HTTP請求(其實最終是調用wsgiref.handlers.BaseHandler中的run方法處理)。WSGIServer通過set_app方法設定一個可調用(callable)的對象作為application,上面提到的handler方法最終會調用設定的application處理request,並返回response。

其中,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在處理request的時候其實做了很多事情,下面我們詳細的過一下。首先給大家分享兩個網上看到的Django流程圖:

Django流程圖1

Django流程圖2
上面的兩張流程圖可以大致描述Django處理request的流程,按照流程圖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返回到瀏覽器,呈現給使用者

上述流程中最主要的幾個部分分別是:Middleware(中介軟體,包括request, view, exception, response),URLConf(url映射關係),Template(模板系統),下面一一介紹一下。

1、Middleware(中介軟體)

Middleware並不是Django所專屬的東西,在其他的Web架構中也有這種概念。在Django中,Middleware可以滲入處理流程的四個階段:request,view,response和exception,相應的,在每個Middleware類中都有rocess_request,process_view, process_response 和 process_exception這四個方法。你可以定義其中任意一個活多個方法,這取決於你希望該Middleware作用於哪個處理階段。每個方法都可以直接返回response對象。

Middleware是在Django BaseHandler的load_middleware方法執行時載入的,載入之後會建立四個列表作為處理器的執行個體變數:

  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項目的配置:

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項目的安裝並不強制要求任何中介軟體,如果你願意,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映射)

如果處理request的中介軟體都沒有直接返回response,那麼Django會去解析使用者請求的URL。URLconf就是Django所支撐網站的目錄。它的本質是URL模式以及要為該URL模式調用的視圖函數之間的映射表。通過這種方式可以告訴Django,對於這個URL調用這段代碼,對於那個URL調用那段代碼。具體的,在Django項目的設定檔中有ROOT_URLCONF常量,這個常量加上根目錄"/",作為參數來建立django.core.urlresolvers.RegexURLResolver的執行個體,然後通過它的resolve方法解析使用者請求的URL,找到第一個匹配的view。

其他有關URLConf的內容,這裡不再具體介紹,大家可以看DjangoBook瞭解。

3、Template(模板)

大部分web架構都有自己的Template(模板)系統,Django也是。但是,Django模板不同於Mako模板和jinja2模板,在Django模板不能直接寫Python代碼,只能通過額外的定義filter和template tag實現。由於本文主要介紹Django流程,模板內容就不過多介紹。


PS: 以上代碼和內容都是基於Django 1.6.5版本,其他版本可能與其不同,請參考閱讀。


Over!

  • 聯繫我們

    該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

    如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

    A Free Trial That Lets You Build Big!

    Start building with 50+ products and up to 12 months usage for Elastic Compute Service

    • Sales Support

      1 on 1 presale consultation

    • After-Sales Support

      24/7 Technical Support 6 Free Tickets per Quarter Faster Response

    • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.