2016-12-12

django 從請(qǐng)求到返回都經(jīng)歷了什么

從runserver說(shuō)起

ruserver是使用django自己的web server,主要用于開(kāi)發(fā)和調(diào)試中驶社, 部署到線上環(huán)境一般使用nginx+uwsgi模式

manage.py 探秘

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

通過(guò)源碼分析可知, ruserserver主要完成兩件事:

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的源碼如下:

通過(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)瓣赂。

django http請(qǐng)求處理流程

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

1. 加載settings.py

在通過(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)

? ? if threading:

? ? ? ? # ThreadingMixIn.daemon_threads indicates how threads will behave on an

? ? ? ? # abrupt shutdown; like quitting the server by the user or restarting

? ? ? ? # by the auto-reloader. True means the server will not wait for thread

? ? ? ? # termination before it quits. This will make auto-reloader faster

? ? ? ? # and will prevent the need to kill the server manually if a thread

? ? ? ? # isn't terminating correctly.

? ? ? ? httpd.daemon_threads = True

? ? 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ì)流程

首先給大家分享兩個(gè)網(wǎng)上看到的Django流程圖:

流程圖一

流程圖二

上面的兩張流程圖可以大致描述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í)例變量:

_request_middleware:process_request方法的列表

_view_middleware:process_view方法的列表

_response_middleware:process_response方法的列表

_exception_middleware:process_exception方法的列表

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

`MIDDLEWARE_CLASSES = [

? ? 'django.middleware.security.SecurityMiddleware',

? ? 'django.contrib.sessions.middleware.SessionMiddleware',

? ? 'django.middleware.common.CommonMiddleware',

? ? 'django.middleware.csrf.CsrfViewMiddleware',

? ? 'django.contrib.auth.middleware.AuthenticationMiddleware',

? ? 'django.contrib.auth.middleware.SessionAuthenticationMiddleware',

? ? 'django.contrib.messages.middleware.MessageMiddleware',

? ? 'django.middleware.clickjacking.XFrameOptionsMiddleware',

]`

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)业汰。以下這張圖可以更好地幫助你理解:

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)容醒串,大家可以參考 [理解curlConf]()

Template(模板)

大部分web框架都有自己的Template(模板)系統(tǒng)执桌,Django也是。但是芜赌,Django模板不同于Mako模板和jinja2模

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末仰挣,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子缠沈,更是在濱河造成了極大的恐慌膘壶,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,029評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件洲愤,死亡現(xiàn)場(chǎng)離奇詭異颓芭,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)柬赐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門亡问,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人躺率,你說(shuō)我怎么就攤上這事玛界。” “怎么了悼吱?”我有些...
    開(kāi)封第一講書(shū)人閱讀 157,570評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵慎框,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我后添,道長(zhǎng)笨枯,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,535評(píng)論 1 284
  • 正文 為了忘掉前任,我火速辦了婚禮馅精,結(jié)果婚禮上严嗜,老公的妹妹穿的比我還像新娘。我一直安慰自己洲敢,他們只是感情好漫玄,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,650評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著压彭,像睡著了一般睦优。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上壮不,一...
    開(kāi)封第一講書(shū)人閱讀 49,850評(píng)論 1 290
  • 那天汗盘,我揣著相機(jī)與錄音,去河邊找鬼询一。 笑死隐孽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的健蕊。 我是一名探鬼主播菱阵,決...
    沈念sama閱讀 39,006評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼缩功!你這毒婦竟也來(lái)了送粱?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 37,747評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤掂之,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后脆丁,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體世舰,經(jīng)...
    沈念sama閱讀 44,207評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,536評(píng)論 2 327
  • 正文 我和宋清朗相戀三年槽卫,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了跟压。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,683評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡歼培,死狀恐怖震蒋,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情躲庄,我是刑警寧澤查剖,帶...
    沈念sama閱讀 34,342評(píng)論 4 330
  • 正文 年R本政府宣布,位于F島的核電站噪窘,受9級(jí)特大地震影響笋庄,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,964評(píng)論 3 315
  • 文/蒙蒙 一直砂、第九天 我趴在偏房一處隱蔽的房頂上張望菌仁。 院中可真熱鬧,春花似錦静暂、人聲如沸济丘。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,772評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)摹迷。三九已至,卻和暖如春辱士,著一層夾襖步出監(jiān)牢的瞬間泪掀,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,004評(píng)論 1 266
  • 我被黑心中介騙來(lái)泰國(guó)打工颂碘, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留异赫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,401評(píng)論 2 360
  • 正文 我出身青樓头岔,卻偏偏與公主長(zhǎng)得像塔拳,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子峡竣,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,566評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容