django源碼分析 python manage.py runserver


django是一個快速開發web應用的框架, 筆者也在django框架上開發不少web應用,閑來無事,就想探究一下django底層到底是如何實現的,本文記錄了筆者對django源碼的分析過程

I believe to become a better developer you MUST get a better understanding of the underlying software systems you use on a daily basis and that includes programming languages, compilers and interpreters, databases and operating systems, web servers and web frameworks. And, to get a better and deeper understanding of those systems you MUST re-build them from scratch, brick by brick, wall by wall.

筆者摘抄了一段話,送給閱讀本文的讀者

正文

如何分析django源碼,筆者選擇從django項目的啟動方式開始 python manage.py runserver,本文主要分析了django項目的啟動流程

#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "order.settings")
    try:
        from django.core.management import execute_from_command_line
    except ImportError:
        # The above import may fail for some other reason. Ensure that the
        # issue is really that Django is missing to avoid masking other
        # exceptions on Python 2.
        try:
            import django
        except ImportError:
            raise ImportError(
                "Couldn't import Django. Are you sure it's installed and "
                "available on your PYTHONPATH environment variable? Did you "
                "forget to activate a virtual environment?"
            )
        raise
    execute_from_command_line(sys.argv)

在manage.py文件中,我們看到啟動文件的入口是 excute_from_command_line(sys.argv)

def execute_from_command_line(argv=None):
    """
    A simple method that runs a ManagementUtility.
    """
    utility = ManagementUtility(argv)
    utility.execute()

這個函數是將命令行參數傳遞給了ManagementUtility類,這個類的execute方法負責執行,這個方法主要是一些django的初始化參數的檢查,以及通過sys.argv獲取命令,得到相應的命令后,執行命令。

execute方法中的部分代碼
...
if settings.configured: # Start the auto-reloading dev server even if the code is broken. # The hardcoded condition is a code smell but we can't rely on a # flag on the command class because we haven't located it yet. if subcommand == 'runserver' and '--noreload' not in self.argv: try: autoreload.check_errors(django.setup)() except Exception: # The exception will be raised later in the child process # started by the autoreloader. Pretend it didn't happen by # loading an empty list of applications. apps.all_models = defaultdict(OrderedDict) apps.app_configs = OrderedDict() apps.apps_ready = apps.models_ready = apps.ready = True ...

execute方法中有一段代碼autoreload.check_errors(django.setup)(),會對django項目進行一些必要的初始化,並檢查初始化的錯誤 django.setup()方法會注冊項目app和配置日志文件,注冊app即對settings.INSTALLED_APPS中的app進行導入,並執行一些初始化方法

進行完所有初始化動作,繼續執行代碼

execute方法中的部分代碼
...
elif self.argv[1:] in (['--help'], ['-h']): sys.stdout.write(self.main_help_text() + '\n') else: self.fetch_command(subcommand).run_from_argv(self.argv) ...

 

self.fetch_command(subcommand)會返回一個BaseCommand類,主要是分析subcommand參數(subcommand是sys.argv里面獲取到的),導入相應的命令類,最后返回類

我們通過分析,runserver參數最終獲取到的命令類是django/contrib/staticfiles/management/command/runserver.py 里的Command

這是Command類的繼承關系圖。Command類通過run_from_argv(self.argv)執行命令

BaseCommand類中run_from_argv方法的部分代碼
...
try: self.execute(*args, **cmd_options) except Exception as e: if options.traceback or not isinstance(e, CommandError): raise ...

 

run_from_argv(self.argv)方法中主要通過execute()來繼續執行,excute中會對django項目進行檢查,然后通過self.handle()繼續執行

 
         
RunserverCommand類里面的handle方法部分代碼
def handle(self, *args, **options):
  ...
  if not self.addr: self.addr = '::1' if self.use_ipv6 else '127.0.0.1' self._raw_ipv6 = self.use_ipv6 self.run(**options)

 

handle()方法里面也進行了一些檢查,然后繼續執行self.run()來啟動服務器

RunserverCommand中的部分代碼
def run(self, **options):
    """
    Runs the server, using the autoreloader if needed
    """
    use_reloader = options['use_reloader']

    if use_reloader:
        autoreload.main(self.inner_run, None, options)
    else:
        self.inner_run(None, **options)

def inner_run(self, *args, **options):
    ...

    try:
        handler = self.get_handler(*args, **options)
        run(self.addr, int(self.port), handler,
            ipv6=self.use_ipv6, threading=threading, server_cls=self.server_cls)
    except socket.error as e:
    
    ...

 

run方法中選擇了啟動的解釋器,最后都是通過inner_run中的run方法來執行,會啟動一個WSGIServer, WSGIServer需要一個回調函數handler(或者application),來執行django視圖里面代碼。

至此,django項目服務器啟動流程完畢,啟動了一個簡單的WSGIServer,開始接受請求,解析請求參數,將請求參數傳遞給回調函數handler(或者application,django框架的核心內容),handler根據參數執行相應的代碼,返回數據給WSGIServer,WSGIServer最終將數據返回給瀏覽器。

關於wsgi可以參考這篇文章,理解Python WSGI

總結:

我認為django啟動流程中對於我們開發者最重要的一步在於django.setup(),里面做了很多初始化的工作,包括導入各個app的models,運行各個app的run函數,配置日志文件。我們如果想要在項目的啟動的時候做一些我們自己的初始化動作,可以選擇在這個地方下手。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM