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函数,配置日志文件。我们如果想要在项目的启动的时候做一些我们自己的初始化动作,可以选择在这个地方下手。
django源码分析 python manage.py runserver的更多相关文章
- django源码分析——本地runserver分析
本文环境python3.5.2,django1.10.x系列 1.根据上一篇文章分析了,django-admin startproject与startapp的分析流程后,根据django的官方实例此时 ...
- django python manage.py runserver 流程
python manage.py runserver 流程分析 版本 python27 django 1.0 搭建可运行的环境 创建python27 虚拟环境 github 下载 django-1.0 ...
- No module named _sqlite3 django python manage.py runserver
linux 执行django(python manage.py runserver),报错No module named _sqlite3,需要安装sqlite-devel,再重新编译安装python ...
- Django源码分析之程序执行入口分析
一般我们开启一个django项目,最简单的方法是进入project 目录,这时目录结构是这样的 然后我们执行python manage.py runserver,程序就开始执行了. 那django是如 ...
- Django源码分析之执行入口
魔法门 一般我们启动django,最简单的方法是进入project 目录,这时目录结构是这样的 然后我们执行python manage.py runserver,程序就开始执行了. 那django是如 ...
- python manage.py runserver指定端口和ip
python manage.py runserver 0.0.0.0:8000 在本地运行程序,python manager.py runserver打开http://127.0.0.1:5000端口 ...
- python manage.py runserver 0.0.0.0:8000
python manage.py runserver 这种命令行,可以在服务器端输入IP:8000直接访问 在 python manage.py runserver 127.0.01:8000 在服务 ...
- django源码分析
原文网址 https://www.jianshu.com/p/17d78b52c732?utm_campaign=maleskine&utm_content=note&utm_medi ...
- Django源码分析之启动wsgi发生的事
前言 好多人对技术的理解都停留在懂得使用即可,因而只会用而不会灵活用,俗话说好奇害死猫,不然我也不会在凌晨1.48的时候决定写这篇博客,好吧不啰嗦了 继续上一篇文章,后我有个问题(上文:&qu ...
随机推荐
- python-os模块使用
1.合并路径 os.path.join("c:\\music\\ap\\0","mav.mp3") 'c:\\music\\ap\\0\\mav.mp3' 2. ...
- 性能调优之Transformation
优化之Aggregator组件 优化之Custom组件 优化之Joiner组件 优化之Lookup组件 优化之Normalizer组件 优化之Sequence Generator组件 优化之Sorte ...
- 华为oj之字符串最后一个单词的长度
题目: 字符串最后一个单词的长度 热度指数:9697 时间限制:1秒 空间限制:32768K 本题知识点: 字符串 题目描述 计算字符串最后一个单词的长度,单词以空格隔开. 输入描述: 一行字符串,非 ...
- IntelliJ IDEA maven项目new里没有package
idea maven项目new里没有package. 如图,idea maven项目new里没有package.: 这是因为java是普通的文件夹,要设置为Source Root 设置好以后可以了.
- .NetCore&Linux&Docker&Portainer踩坑历险记
最近有一个云服务器和数据库的迁移任务,踩坑爬坑无数次,觉得必须要记录一下.大家瓜子花生准备好,听我慢慢讲故事#手动笑哭#. 故事背景 公司是做电商业务的,在天猫有几家旗舰店数据量也很大.阿里有一个称为 ...
- API网关模式
什么是网关 网关一词来源于计算机网络中的定义,网关(Gateway)又称网间连接器.协议转换器.网关的准确定义是: 两个计算机程序或系统之间的连接,网关作为两个程序之间的门户,允许它们通过不同计算机之 ...
- leetcode — best-time-to-buy-and-sell-stock-iii
/** * Source : https://oj.leetcode.com/problems/best-time-to-buy-and-sell-stock-iii/ * * * Say you h ...
- ES6躬行记(20)——类
ES6正式将类(Class)的概念在语法层面标准化,今后不必再用构造函数模拟类的行为.而ES6引入的类本质上只是个语法糖(即代码更为简洁.语义更为清晰),其大部分功能(例如继承.封装和复用等)均可在E ...
- 封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil
封装一个基于NLog+NLog.Mongo的日志记录工具类LogUtil,代码比较简单,主要是把MongoTarget的配置.FileTarget的配置集成到类中,同时利用缓存依赖来判断是否需要重新创 ...
- SpringCloud系列——Feign 服务调用
前言 前面我们已经实现了服务的注册与发现(请戳:SpringCloud系列——Eureka 服务注册与发现),并且在注册中心注册了一个服务myspringboot,本文记录多个服务之间使用Feign调 ...