在此写下我在阅读Django源码时的心得体会。
选择Django版本为3.1.3.
本人是一个python入门选手,这是我第一次阅读大型框架源码,并不知道该以何种顺序阅读。故此,阅读顺序完全按照个人习惯,从框架如何开始建立项目为头,慢慢解析。
解析中会穿插着我的一些个人总结,及一些需要后续深入了解展开解析的内容。
解析中的任何不足和错误,请大家积极指出。谢谢各位!
想建立一个django项目,第一步就是需要在终端使用 django-admin startproject project 命令生成一个django项目框架。
django-admin (命令的路径此处就不多说了。)在终端中找到命令路径,通过cat命令,可以看到下面内容:
$ cat django-admin
#!/home/MyProject/env/env-import-python3.6/bin/python3.6
# -*- coding: utf-8 -*-
import re
import sys
from django.core.management import execute_from_command_line
if __name__ == '__main__':
sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
sys.exit(execute_from_command_line())
sys.arg:是sys模块的一个全局变量,也称sys模块的一个属性。argv本身为一个list类型的对象,该对象持有的第1个元素是命令行中传入的模块名、从第2个元素开始(含),均为命令行中传入的参数。
r’(-script.pyw|.exe)?$’ 这个正则挺简单的。作用就是把字符串中结尾处的 .exe 或者 -script.pyw 替换掉。因为不同系统下,文件名后缀不同,替换掉不同的部分,统一程序名。
execute_from_command_line 方法在core.management.init.py文件中。
def execute_from_command_line(argv=None):
"""Run a ManagementUtility."""
utility = ManagementUtility(argv)
utility.execute()
ManagementUtility 是封装的django-admin和manage.py程序的逻辑方法。
execute() 方法:获取命令行参数,找出需要运行的子命令,创建一个适合该命令的解析器,然后运行它。
需要运行的命令赋值给 subcommand 。
创建一个解析器实例。这个解析器的类CommandParser在core.management.base.py中,是基于ArgumentParser的。ArgumentParser位于python的argparse 模块,可以让人轻松编写用户友好的命令行接口。
创建解析器实例之后,对命令行传输过来的参数进行合理性判断,并预处理pythonpath和settings 加入到环境变量。
在运行django-admin 创建项目的时候,还没有自己配置的settings,故使用的是默认的conf下的global_settings.py。
确认了settings之后,进行校验,具体的校验代码在conf中。此处先不展开。
settings校验之后,判断要运行的子命令:此处分为runserver 命令和其他命令两个分支。(runserver后续展开)。
创建项目时,此处传入的命令是 startproject .
运行 django.setup()方法(在django.init.py)。
接下来是一个自动补全的调用 self.autocomplete(). 方法中说,如果用户不设置,就跳过。我没有使用过,这里就直接跳过了。(有用过的朋友,欢迎指教~)
然后是关于 help 和 version 的调用。如果命令行中有这些参数,会在终端输出关于该命令的帮助或版本信息。
最后,就是查找并执行我们输入的子命令了。
fetch_command()方法中,先用get_commands()检索所有的子命令模块。
get_commands()方法使用了python3.2之后新添加的lru_cache 装饰器。这是一个很好的缓存机制,有兴趣的朋友可以自行去了解。
get_commands()方法使用pkgutil (python的包管理工具模块)中的iter_modules方法返回一个{command_name: app_name}形式的字典。
方法中还对用户自己定义的commands方法进行了检索,这个是后话,容后再叙。
get_commands()返回了命令字典后,fetch_command()对传参进来的子命令进行校验,是否在已经定义了的命令中。
确认命令存在之后,判断该命令是否已经加载,如果已经加载,直接使用。如果没有,加载该命令并返回Command类。
(Commmand类继承自management.templates.py中的template类。template类又是继承自management.base.py中的BaseCommand类。)
调用实例化之后命令的run_from_argv()方法,设置所有要求的环境变量,进行系统自检。最终执行handle()方法,把conf下project_template目录中的所有内容,修改名称后缀之后复制到要创建项目的位置。
至此,项目创建完成,django-admin startproject 命令结束。
以上就是django-admin startproject [name] 命令的简略解析。
通过对整个流程源码的阅读可以看出,django-admin startproject 命令其实简单来说就是 通过解析命令行传输进来的参数,把位于conf下的project_template文件夹内容更名之后复制到用户所设定的位置。
流程大部分的源码,都是django-admin 和 manage命令复用的。startproject 也只是诸多子命令中的一个,由此可见,我们在项目中,可以根据需求,自助封装子命令。具体方法我们后续解析。
其中涉及到的 BaseCommand,基于BaseCommand的TemplateCommand,需要再深入阅读。
解析完django-admin startproject 命令,我顺势整体解析coer.management模块。
这个模块主要是完成django-admin 和 manage 命令的各种功能。
该模块的目录结构如下:
这个文件中包含了5个方法和一个 ManagementUtility 类。
包含4个方法
从__init__.py的源码中,我们可以看出django对于命令行命令的解析和执行流程。按照这个流程,我们可以在项目中封装自己的命令。
流程:在已配置的app中,建立management包(需要包含__init__.py文件),在management包中在创建一个commands包(需要包含__init__.py文件),在commands包就可以创建属于我们自己的命令文件了(文件名即为命令名)。命令文件中必须包含一个基于BaseCommand(位于core.management.base)的Command类,这个类就是执行命令时所需要实例化的类。类中要包含 handle 方法。handle方法要接受 *args **options 参数。这个handle方法就是执行命令时最终调用的方法,也就是命令的逻辑内容。
按照上述流程创建好一个命令之后,可以在终端使用 python manage.py [name] 来调用。也可以在程序中使用call_command()这个私有api调用。
可被django-admin 和 manage.py 执行的命令的基类。
包含8个类和2个方法:
命令基类。
BEGIN;
and COMMIT;
。app命令基类,继承自BaseCommand.
label命令基类,继承自BaseCommand.
这个模块是用来设置终端颜色显示方案。包含4个方法,一个类。
如果环境变量中没有设置DJANGO_COLORS变量,使用django.utils.termcolors的颜色配置。
返回一个用来刷新数据库的sql语句列表。
为每个应用程序发出预迁移信号。
为每个应用程序发出迁移后信号。
此类是用来复制Django app 布局模板或Django project 布局模板到指定的目录中,来创建app或project。
此中包含9个方法。
management的工具集。这里就不展开了,都是很简单的方法。
所有django 内置的子命令。
检查整个django项目中可能存在的错误。
这个命令引入了core.checks模块。
这个命令是Django官方提供的项目国际化命令,这个命令需要配合makemessages命令使用。makemessages命令生成一个po文件,compilemessages把po文件编译生成mo文件。
具体国际化的使用方式,我从网上浏览学习的时候发现了这个文章,介绍的很不错。https://www.jb51.net/article/143337.htm大家有兴趣的可以去学习。
当项目的缓存方式使用数据库缓存时,执行此命令自动生成缓存使用数据库表。python manage.py createcachetable
python manage.py dbshell
Django 会自动进入在settings.py中设置的数据库,如果是 MySQL 或 postgreSQL,会要求输入数据库用户密码。
我们在使用djnago项目的时候,都会根据需要,配置项目中settings.py。Django默认的settings是django.conf.global_settings.py。如果我们需要对照我们写的settings与默认settings的区别,可以使用此命令。
django在编译时,先载入global_settings.py中的配置,然后加载指定的settings文件,重写改变的设定。
在其他module中,如果希望访问settings文件,可以使用from django.conf import settings来导入。不要导入global_settings或者我们自己写的settings。因为,django.conf.setting提取了global_settings和我们自己写的settings里面的内容。相比直接导入自己写的settings文件和global_settings文件,它提供给我们的是一个接口。可以实现解耦的作用。
此命令用于导出项目数据库中的数据
python manage.py dumpdata -o /home/b.json accounts.User --indent 2
-o 后面接输出文件路径
后边的accounts.User 是app名和model名
–indent 可以设置导出的格式。
此命令可以清空数据库中所有数据,留下空表
Django用来反向生成Model的方法。此命令可以把配置中连接的数据库中的数据表,反向生成在指定app下的model中。
python manage.py inspecdb > [your app name]\models.py
主要用于单元测试时测试数据的导入。
国际化命令,见上compilemessages命令。
python manage.py makemigrations这个命令是记录我们对models.py的所有改动,并且将这个改动迁移到migrations这个文件下生成一个文件例如:0001文件。
此命令是把执行makemigrations之后所记录的改动,执行到数据库。
开发测试时常用到的,用来在本地通过Django内置服务器启动项目。
发送测试邮件,验证配置中的邮箱是否有效。
python manage shell 命令,将自动帮你处理DJANGO_SETTINGS_MODULE。这样在命令行中,即可直接对项目进行操作无需在配置环境变量。
执行python manage showmigrations 命令,将在终端看到当前项目可以获得的所有迁移信息。
打印出将数据库中的所有表返回到刚安装后的状态所需的SQL语句列表。即如何实现的flush命令。
打印出 migration 所需执行的sql语句。
打印用于顺序重置给定应用程序名称的SQL语句。
压缩合并迁移文件
新建一个app。
新建一个项目。
用来测试项目模块功能。命令行中需输入要测试的功能模块
python manage.py test …
启用一个测试开发服务,命令行输入fixture路径来提供需要用到数据。
core.management 是管理Django命令的模块。其中包含的内置命令是用来快速搭建项目并为开发者提供一些便捷的开发测试环境。
在准备使用这一模块建立属于自己的命令或者想对源码有深入的理解,需要提前熟悉以下Python库:
argparse,concurrent.futures。
整个management模块简单理解其实就是基于argparse库的二次开发。