Django源碼分析(二):runserver

起步

上節知悉了 django 是如何作到自動重啓的以後,那麼接下來了解下它是如何運行起一個 web 服務的。python

開始

很熟悉的命令web

經過下面的命令,咱們即可將 django 跑起來。那麼它發生了什麼呢?django

python3 manage.py runserver瀏覽器

簡單的 web 服務

在此以前,根據 django 運行的服務,咱們也利用 wsgiref 這個模塊實現一個簡單的 web 服務。網絡

# server_demo.py

from wsgiref.simple_server import WSGIServer, WSGIRequestHandler

def demo_app(environ, start_response):
    from io import StringIO
    stdout = StringIO()
    print("Hello world!", file=stdout)
    print(file=stdout)
    h = sorted(environ.items())
    for k, v in h:
        print(k, '=', repr(v), file=stdout)
    start_response("200 OK", [('Content-Type', 'text/plain; charset=utf-8')])
    return [stdout.getvalue().encode("utf-8")]


s = WSGIServer(("127.0.0.1", 1234), WSGIRequestHandler)
# 設置應用,注意了這裏不必定非是個函數,但是一切可調用的對象
# 例如 函數、方法、類或實現了 __call__ 方法的實例
s.set_app(demo_app)
# 開始監聽請求,這裏應該是用的 poll 或者 selector 的網絡模型。
s.serve_forever()

複製代碼

運行起來 server_demo.py 這個文件,而後經過瀏覽器訪問 127.0.0.1:1234,會發現頁面響應了一堆內容(沒必要關心展現的內容具體是什麼)。app

django 的服務

接下來觀察源碼。socket

django/core/servers/basehttp.py 下的 run 方法函數

def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
    server_address = (addr, port)
    if threading:
        httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
    else:
        httpd_cls = server_cls
    httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
    if threading:
        httpd.daemon_threads = True
    # 這裏的 wsgi_handler 來自於
    # from django.core.handlers.wsgi import WSGIHandler
    httpd.set_app(wsgi_handler)
    httpd.serve_forever()

複製代碼

WSGIHandler

這是一個 wsgi 應用,它被定義在了 proj/wsgi.py 下的 application 屬性。(application 對應剛剛上面代碼中出現的 wsgi_handler)spa

application 這個屬性對應的是個 get_wsgi_application 函數,該函數調用的過程當中,針對 django.core.handlers.wsgi.WSGIHandler 這個類進行了實例化,在 __init__ 方法中,加載了 django 中間件。code

# django.core.handlers.wsgi.py
class WSGIHandler(base.BaseHandler):
    request_class = WSGIRequest

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # 載入中間件(注意:這裏很關鍵。)
        self.load_middleware()
複製代碼

總結

至此,咱們瞭解到了 django 的服務是從 django/core/servers/basehttp.py 下的 run 方法啓動了一個 wsgi 服務。這個可調用的對象來自於 django.core.handlers.wsgi.WSGIHandler,這個類在實例化(__init__)的過程當中,加載了中間件。

咱們也更應該瞭解下 wsgi

相關文章
相關標籤/搜索