摘要:所以,我按照自己的邏輯總結(jié)了一下項目的運(yùn)行方式和對的基本處理流程。二請求處理流程和其他框架一樣,的處理流程基本類似接受,返回內(nèi)容。在中,中間件組件用字符串表示指向中間件類名的完整路徑。
之前在網(wǎng)上看過一些介紹Django處理請求的流程和Django源碼結(jié)構(gòu)的文章,覺得了解一下這些內(nèi)容對開發(fā)Django項目還是很有幫助的。所以,我按照自己的邏輯總結(jié)了一下Django項目的運(yùn)行方式和對Request的基本處理流程。
一、Django的運(yùn)行方式運(yùn)行Django項目的方法很多,這里主要介紹一下常用的方法。一種是在開發(fā)和調(diào)試中經(jīng)常用到runserver方法,使用Django自己的web server;另外一種就是使用fastcgi,uWSGIt等協(xié)議運(yùn)行Django項目,這里以uWSGIt為例。
1、runserver方法runserver方法是調(diào)試Django時經(jīng)常用到的運(yùn)行方式,它使用Django自帶的WSGI Server運(yùn)行,主要在測試和開發(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的源碼,你會發(fā)現(xiàn)上面的命令其實(shí)是通過Django的execute_from_command_line方法執(zhí)行了內(nèi)部實(shí)現(xiàn)的runserver命令,那么現(xiàn)在看一下runserver具體做了什么。。
看了源碼之后,可以發(fā)現(xiàn)runserver命令主要做了兩件事情:
解析參數(shù),并通過 django.core.servers.basehttp.get_internal_wsgi_application 方法獲取 wsgi handler ;
根據(jù)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會先根據(jù)settings中的WSGI_APPLICATION來獲取handler;在創(chuàng)建project的時候,Django會默認(rèn)創(chuàng)建一個wsgi.py文件,而settings中的WSGI_APPLICATION配置也會默認(rèn)指向這個文件??匆幌逻@個wsgi.py文件,其實(shí)它也和上面的邏輯一樣,最終調(diào)用get_wsgi_application實(shí)現(xiàn)。
2、uWSGI方法uWSGI+Nginx的方法是現(xiàn)在最常見的在生產(chǎn)環(huán)境中運(yùn)行Django的方法,本人的博客也是使用這種方法運(yùn)行,要了解這種方法,首先要了解一下WSGI和uWSGI協(xié)議。
WSGI,全稱Web Server Gateway Interface,或者Python Web Server Gateway Interface,是為Python語言定義的Web服務(wù)器和Web應(yīng)用程序或框架之間的一種簡單而通用的接口,基于現(xiàn)存的CGI標(biāo)準(zhǔn)而設(shè)計的。WSGI其實(shí)就是一個網(wǎng)關(guān)(Gateway),其作用就是在協(xié)議之間進(jìn)行轉(zhuǎn)換。(PS: 這里只對WSGI做簡單介紹,想要了解更多的內(nèi)容可自行搜索)
uWSGI是一個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配置如下:
: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和運(yùn)行的命令如下:
sudo pip install uwsgi uwsgi --pidfile=/var/run/geek-blog.pid -x uwsgi.xml --uid blog --gid nogroup
uWSGI和Nginx一起使用的配置方法就不在這里說明了,網(wǎng)上教程很多,需要的可以自行搜索。
二、HTTP請求處理流程Django和其他Web框架一樣,HTTP的處理流程基本類似:接受request,返回response內(nèi)容。Django的具體處理流程大致如下圖所示:
加載project settings在通過django-admin.py創(chuàng)建project的時候,Django會自動生成默認(rèn)的settings文件和manager.py等文件,在創(chuàng)建WSGIServer之前會執(zhí)行下面的引用:
from django.conf import settings
上面引用在執(zhí)行時,會讀取os.environ中的DJANGO_SETTINGS_MODULE配置,加載項目配置文件,生成settings對象。所以,在manager.py文件中你可以看到,在獲取WSGIServer之前,會先將project的settings路徑加到os路徑中。
不管是使用runserver還是uWSGI運(yùn)行Django項目,在啟動時都會調(diào)用django.core.servers.basehttp中的run()方法,創(chuàng)建一個django.core.servers.basehttp.WSGIServer類的實(shí)例,之后調(diào)用其serve_forever()方法啟動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í)例的時候會指定HTTP請求的Handler,上述代碼使用WSGIRequestHandler。當(dāng)用戶的HTTP請求到達(dá)服務(wù)器時,WSGIServer會創(chuàng)建WSGIRequestHandler實(shí)例,使用其handler方法來處理HTTP請求(其實(shí)最終是調(diào)用wsgiref.handlers.BaseHandler中的run方法處理)。WSGIServer通過set_app方法設(shè)置一個可調(diào)用(callable)的對象作為application,上面提到的handler方法最終會調(diào)用設(shè)置的application處理request,并返回response。
其中,WSGIServer繼承自wsgiref.simple_server.WSGIServer,而WSGIRequestHandler繼承自wsgiref.simple_server.WSGIRequestHandler,wsgiref是Python標(biāo)準(zhǔn)庫給出的WSGI的參考實(shí)現(xiàn)。其源碼可自行到wsgiref參看,這里不再細(xì)說。
處理Request第二步中說到的application,在Django中一般是django.core.handlers.wsgi.WSGIHandler對象,WSGIHandler繼承自django.core.handlers.base.BaseHandler,這個是Django處理request的核心邏輯,它會創(chuàng)建一個WSGIRequest實(shí)例,而WSGIRequest是從http.HttpRequest繼承而來
返回Response上面提到的BaseHandler中有個get_response方法,該方法會先加載Django項目的ROOT_URLCONF,然后根據(jù)url規(guī)則找到對應(yīng)的view方法(類),view邏輯會根據(jù)request實(shí)例生成并返回具體的response。
在Django返回結(jié)果之后,第二步中提到wsgiref.handlers.BaseHandler.run方法會調(diào)用finish_response結(jié)束請求,并將內(nèi)容返回給用戶。
上述的第三步和第四步邏輯只是大致說了一下處理過程,Django在處理request的時候其實(shí)做了很多事情,下面我們詳細(xì)的過一下。首先給大家分享兩個網(wǎng)上看到的Django流程圖:
Django流程圖1
Django流程圖2
上面的兩張流程圖可以大致描述Django處理request的流程,按照流程圖2的標(biāo)注,可以分為以下幾個步驟:
1. 用戶通過瀏覽器請求一個頁面 2. 請求到達(dá)Request Middlewares,中間件對request做一些預(yù)處理或者直接response請求 3. URLConf通過urls.py文件和請求的URL找到相應(yīng)的View 4. View Middlewares被訪問,它同樣可以對request做一些處理或者直接返回response 5. 調(diào)用View中的函數(shù) 6. View中的方法可以選擇性的通過Models訪問底層的數(shù)據(jù) 7. 所有的Model-to-DB的交互都是通過manager完成的 8. 如果需要,Views可以使用一個特殊的Context 9. Context被傳給Template用來生成頁面 a. Template使用Filters和Tags去渲染輸出 b. 輸出被返回到View c. HTTPResponse被發(fā)送到Response Middlewares d. 任何Response Middlewares都可以豐富response或者返回一個完全不同的response e. Response返回到瀏覽器,呈現(xiàn)給用戶
上述流程中最主要的幾個部分分別是:Middleware(中間件,包括request, view, exception, response),URLConf(url映射關(guān)系),Template(模板系統(tǒng)),下面一一介紹一下。
1、Middleware(中間件)Middleware并不是Django所獨(dú)有的東西,在其他的Web框架中也有這種概念。在Django中,Middleware可以滲入處理流程的四個階段:request,view,response和exception,相應(yīng)的,在每個Middleware類中都有rocess_request,process_view, process_response 和 process_exception這四個方法。你可以定義其中任意一個活多個方法,這取決于你希望該Middleware作用于哪個處理階段。每個方法都可以直接返回response對象。
Middleware是在Django BaseHandler的load_middleware方法執(zhí)行時加載的,加載之后會建立四個列表作為處理器的實(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路徑。例如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項目的安裝并不強(qiáng)制要求任何中間件,如果你愿意,MIDDLEWARE_CLASSES可以為空。中間件出現(xiàn)的順序非常重要:在request和view的處理階段,Django按照MIDDLEWARE_CLASSES中出現(xiàn)的順序來應(yīng)用中間件,而在response和exception異常處理階段,Django則按逆序來調(diào)用它們。也就是說,Django將MIDDLEWARE_CLASSES視為view函數(shù)外層的順序包裝子:在request階段按順序從上到下穿過,而在response則反過來。以下兩張圖可以更好地幫助你理解:
Django Middleware流程1
Django Middleware流程圖2
如果處理request的中間件都沒有直接返回response,那么Django會去解析用戶請求的URL。URLconf就是Django所支撐網(wǎng)站的目錄。它的本質(zhì)是URL模式以及要為該URL模式調(diào)用的視圖函數(shù)之間的映射表。通過這種方式可以告訴Django,對于這個URL調(diào)用這段代碼,對于那個URL調(diào)用那段代碼。具體的,在Django項目的配置文件中有ROOT_URLCONF常量,這個常量加上根目錄"/",作為參數(shù)來創(chuàng)建django.core.urlresolvers.RegexURLResolver的實(shí)例,然后通過它的resolve方法解析用戶請求的URL,找到第一個匹配的view。
其他有關(guān)URLConf的內(nèi)容,這里不再具體介紹,大家可以看DjangoBook了解。
3、Template(模板)大部分web框架都有自己的Template(模板)系統(tǒng),Django也是。但是,Django模板不同于Mako模板和jinja2模板,在Django模板不能直接寫Python代碼,只能通過額外的定義filter和template tag實(shí)現(xiàn)。由于本文主要介紹Django流程,模板內(nèi)容就不過多介紹。
PS: 以上代碼和內(nèi)容都是基于Django 1.6.5版本,其他版本可能與其不同,請參考閱讀。
Over!
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/37466.html
摘要:面試的心得體會簡歷制作我做了兩份簡歷,用兩個手機(jī)賬號,兩個簡歷名字,分別在各個招聘網(wǎng)站投了雙份簡歷,一個是數(shù)據(jù)分析的簡歷一個是全棧開發(fā)的簡歷,我真正接觸快年,不管是學(xué)習(xí)還是工作學(xué)到的東西,這兩年大概掌握了前端爬蟲數(shù)據(jù)分析機(jī)器學(xué)習(xí)技術(shù), showImg(https://upload-images.jianshu.io/upload_images/13090773-b96aac7e974c...
摘要:比如說如果我們這里把改成,而我們在中寫的是,即一個空字符串。那么最終匹配的就是加上一個空字符串,即。在博客首頁視圖追夢人物的博客的評論區(qū)留言。 Django 處理 HTTP 請求 Web 應(yīng)用的交互過程其實(shí)就是 HTTP 請求與響應(yīng)的過程。無論是在 PC 端還是移動端,我們通常使用瀏覽器來上網(wǎng),上網(wǎng)流程大致來說是這樣的: 我們打開瀏覽器,在地址欄輸入想訪問的網(wǎng)址,比如 http://...
摘要:要使用協(xié)議我們不可能自己實(shí)現(xiàn)一個,現(xiàn)在比較流行的解決方案就是使用套接字編程,已經(jīng)幫我們實(shí)現(xiàn)了協(xié)議的細(xì)節(jié),我們可以直接拿來使用不用關(guān)心細(xì)節(jié)。 前幾天寫了 淺談cgi、wsgi、uwsgi 與 uWSGI 等一些 python web 開發(fā)中遇到的一些名詞的理解,今天博主就根據(jù) wsgi 標(biāo)準(zhǔn)實(shí)現(xiàn)一個 web server,并嘗試用它來跑 Django、tornado 框架的 app。 編...
摘要:按目前的發(fā)展趨勢,未來的主流版為。這里介紹一個強(qiáng)大的軟件,它實(shí)現(xiàn)和兩個版本的共存,并且可以相互轉(zhuǎn)換。應(yīng)用程序是包和環(huán)境管理器。另外值得一提的是,并不僅僅管理的工具包,它也能安裝非的包。實(shí)際上,腳本和程序使用的默認(rèn)是附帶的。 前言 初學(xué)Python時,總是被python的兩個不太兼容的版本搞得頭昏腦脹。按目前的發(fā)展趨勢,python未來的主流版為python3。但是我們經(jīng)常會遇到一些很有...
摘要:比較流行的解決方案是允許用戶通過第三方登錄,即可以通過微博這類知名社區(qū)的授權(quán),從而登錄你的小站,免去了注冊的麻煩。微博微信的登錄方式大致都遵循這個流程本章雖然加載了微博的接口,但是限于篇幅并沒有配置,請讀者查閱官方文檔去實(shí)現(xiàn)。 現(xiàn)在我們已經(jīng)擁有一個可以進(jìn)行用戶本地登錄的博客系統(tǒng)了。如果有人欣賞你的文章,說不定就會注冊成為本地用戶,并和你好好交流一番。 但頭疼的是,用戶可能每天都在互聯(lián)網(wǎng)...
閱讀 2536·2023-04-25 14:54
閱讀 609·2021-11-24 09:39
閱讀 1819·2021-10-26 09:51
閱讀 3867·2021-08-21 14:10
閱讀 3494·2021-08-19 11:13
閱讀 2700·2019-08-30 14:23
閱讀 1817·2019-08-29 16:28
閱讀 3364·2019-08-23 13:45