Django框架的源码解析

news2024/11/17 11:02:56
  • 简述
  • 从django-admin startproject [name]开始
    • 小结
  • django.core.management
    • init.py
        • 1. 5个方法
        • 2. ManagementUtility 类
      • 小结
    • base.py
        • 1. 2个方法:
        • 2. CommandError(Exception):
        • 3. SystemCheckError(CommandError):
        • 4. CommandParser(ArgumentParser):
        • 5. DjangoHelpFormatter(HelpFormatter):
        • 6. OutputWrapper(TextIOBase):
        • 7. BaseCommand:
        • 8. AppCommand(BaseCommand):
        • 9. LabelCommand(BaseCommand):
    • color.py
    • sql.py
        • def sql_flush(style, connection, only_django=False, reset_sequences=True, allow_cascade=False):
        • emit_pre_migrate_signal(verbosity, interactive, db, **kwargs):
        • emit_post_migrate_signal(verbosity, interactive, db, **kwargs):
    • templates.py
        • class TemplateCommand(BaseCommand):
    • utils.py
    • commands
        • check.py
        • compilemessages.py
        • createcachetable.py
        • dbshell.py
        • diffsettings.py
        • dumpdata.py
        • flush
        • inspectdb
        • loaddata
        • makemessages
        • makemigrations
        • migrate
        • runserver
        • sendtestemail
        • shell
        • showmigrations
        • sqlflush
        • sqlmigrate
        • sqlsequencereset
        • squashmigration
        • startapp
        • startproject
        • test
        • testserver
  • 总结

简述

在此写下我在阅读Django源码时的心得体会。
选择Django版本为3.1.3.
本人是一个python入门选手,这是我第一次阅读大型框架源码,并不知道该以何种顺序阅读。故此,阅读顺序完全按照个人习惯,从框架如何开始建立项目为头,慢慢解析。
解析中会穿插着我的一些个人总结,及一些需要后续深入了解展开解析的内容。
解析中的任何不足和错误,请大家积极指出。谢谢各位!

从django-admin startproject [name]开始

想建立一个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文件中。

img

def execute_from_command_line(argv=None):
    """Run a ManagementUtility."""
    utility = ManagementUtility(argv)
    utility.execute()

ManagementUtility 是封装的django-admin和manage.py程序的逻辑方法。
execute() 方法:获取命令行参数,找出需要运行的子命令,创建一个适合该命令的解析器,然后运行它。

img

需要运行的命令赋值给 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)。

img

接下来是一个自动补全的调用 self.autocomplete(). 方法中说,如果用户不设置,就跳过。我没有使用过,这里就直接跳过了。(有用过的朋友,欢迎指教~)

然后是关于 help 和 version 的调用。如果命令行中有这些参数,会在终端输出关于该命令的帮助或版本信息。

最后,就是查找并执行我们输入的子命令了。

img

fetch_command()方法中,先用get_commands()检索所有的子命令模块。

img

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.core.management

解析完django-admin startproject 命令,我顺势整体解析coer.management模块。
这个模块主要是完成django-admin 和 manage 命令的各种功能。

该模块的目录结构如下:

img

init.py

这个文件中包含了5个方法和一个 ManagementUtility 类。

1. 5个方法
  • find_commands():传入一个地址参数,返回一个包含所有有效命令的列表。
  • load_command_class():传入应用名和命令名,返回一个Command类的实例。
  • get_commands():检索所有命令。django.core包下的命令必定会被检索到。如果项目中有用户自主封装的命令,也会被一并检索。返回一个{command_name: app_name}类型的字典。
  • call_command():这是一个私有接口,通过传入 命令名或命令实例 和 各种参数,来直接调用命令。
  • execute_from_command_line():实例化一个ManagementUtility ,并执行。django-admin和manage 中都是调用的这个方法。
2. ManagementUtility 类

包含4个方法

  • main_help_text():以字符串形式返回脚本的主帮助文档。
  • fetch_command():匹配命令,如果正确匹配上命令,返回命令实例。
  • autocomplete():
  • execute():验证命令并执行。创建一个CommandParser实例解析参数。其中当子命令为 runserver 时, 涉及到一个autoreload 模块。我们后续解析到utils工具模块的时候再看。

小结

从__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调用。

base.py

可被django-admin 和 manage.py 执行的命令的基类。
包含8个类和2个方法:

1. 2个方法:
  • handle_default_options(): 设置配置文件和pythonpath。
  • no_translations():一个装饰器,强制命令在禁用翻译的情况下运行。(translation模块我现在还不知道是干嘛的,后边解析。。)
2. CommandError(Exception):
  • 继承自Exception的一个命令异常类,重写了__init__方法,添加了一个returncode的参数。
3. SystemCheckError(CommandError):
4. CommandParser(ArgumentParser):
  • 自定义的ArgumentParser类,以改进某些错误消息并在某些情况下阻止SystemExit,因为当以编程方式调用命令时,SystemExit是不可接受的。
  • 多了两个参数,missing_args_message和called_from_command_line。
  • error() 方法中实现了如果命令是在命令行中执行的,出现异常则直接exit,如果是进程调用则抛出异常,至于是否退出,需要看类实例化调用处的处理。比如__init__.py ManagementUtility() 的 excute()方法中的如下代码则不退出:

img

5. DjangoHelpFormatter(HelpFormatter):
  • 自定义帮助格式化程序。
6. OutputWrapper(TextIOBase):
7. BaseCommand:

命令基类。

  • 几个可能影响流程中各个步骤的属性:
    help : 关于命令的简短描述,会在帮助信息中打印出来。
    output_transaction: 一个布尔类型的标志,标志命令是否输出SQL声明。默认为FALSE,如果设置为TRUE的话,会自动包装上 BEGIN; and COMMIT;
    requires_system_checks:布尔类型属性,默认为True,在执行命令之前,整个django项目将会检查错误。
    requires_migrations_checks:布尔类型属性,如果为TRUE,在磁盘上的migrations设置和数据库中的migrations设置不匹配时,会打印出一个warning。
    stealth_options:一个包含所有 命令会用到的 未被参数解析器定义的 可选参数。
  • get_version(): 返回django版本。
  • create_parser():创建解析器实例,并添加几个默认可选参数。
  • add_arguments():子类重写。
  • print_help():打印帮助信息。
  • run_from_argv():设置要求的环境变化,然后执行execute()。
  • execute():执行handle()方法。执行之前进行一系列检查。
  • check():使用core.checks模块,对整个django项目检查错误。
  • check_migrations():当在磁盘上的migrations设置和数据库中的migrations设置不匹配时,打印出一个warning。
  • handle():子类中需重写此方法,未重写的话,会raise异常。
8. AppCommand(BaseCommand):

app命令基类,继承自BaseCommand.

  • add_arguments():重写基类中的add_arguments(),执行parser对象的add_argument方法添加一个 nargs='+'的参数,表示在命令行中可以输入一个或多个应用程序标签。
  • handle():引入django.apps 模块,使用模块中的get_app_config()方法,对命令行中传输进来的args参数列表进行遍历,返回应用程序的配置list,然后遍历应用程序的配置list,逐个传入handle_app_config方法并执行。返回结果。
  • handle_app_config():子类中需重写的方法。未重写的话,会raise异常。
9. LabelCommand(BaseCommand):

label命令基类,继承自BaseCommand.

  • add_arguments():重写基类中的add_arguments(),执行parser对象的add_argument方法添加一个 nargs='+'的参数,表示在命令行中可以输入一个或多个标签。
  • handle():遍历传入的labels列表,执行handle_label方法。返回结果。
  • handle_label():子类中需重写的方法。未重写的话,会raise异常。

color.py

这个模块是用来设置终端颜色显示方案。包含4个方法,一个类。
如果环境变量中没有设置DJANGO_COLORS变量,使用django.utils.termcolors的颜色配置。

sql.py

def sql_flush(style, connection, only_django=False, reset_sequences=True, allow_cascade=False):

返回一个用来刷新数据库的sql语句列表。

emit_pre_migrate_signal(verbosity, interactive, db, **kwargs):

为每个应用程序发出预迁移信号。

emit_post_migrate_signal(verbosity, interactive, db, **kwargs):

为每个应用程序发出迁移后信号。

templates.py

class TemplateCommand(BaseCommand):

此类是用来复制Django app 布局模板或Django project 布局模板到指定的目录中,来创建app或project。
此中包含9个方法。

  • add_arguments(self, parser):添加命令行参数,包括name,directory,–template,–extension,–name
  • handle(self, app_or_project, name, target=None, **options):主要执行的创建app或project的逻辑方法。
  • handle_template(self, template, subdir):明确app或project模板的地址。
  • validate_name(self, name, name_or_dir=‘name’):验证name,并查看是否可以导入,如果可以导入,证明已存在,raise异常。
  • download(self, url):下载传入的url文件,并返回文件名。
  • splitext(self, the_path):分割传入的文件路径。类似os.path.splitext,增加了对tar文件的特殊处理。
  • extract(self, filename):将给定的文件临时解压缩到,并返回包含提取内容的目录的路径。
  • is_url(self, template): 如果template的地址格式类似url则返回True,
  • make_writeable(self, filename):确保文件是可写的。

utils.py

management的工具集。这里就不展开了,都是很简单的方法。

commands

所有django 内置的子命令。

check.py

检查整个django项目中可能存在的错误。
这个命令引入了core.checks模块。

compilemessages.py

这个命令是Django官方提供的项目国际化命令,这个命令需要配合makemessages命令使用。makemessages命令生成一个po文件,compilemessages把po文件编译生成mo文件。
具体国际化的使用方式,我从网上浏览学习的时候发现了这个文章,介绍的很不错。https://www.jb51.net/article/143337.htm大家有兴趣的可以去学习。

createcachetable.py

当项目的缓存方式使用数据库缓存时,执行此命令自动生成缓存使用数据库表。python manage.py createcachetable

dbshell.py

python manage.py dbshell
Django 会自动进入在settings.py中设置的数据库,如果是 MySQL 或 postgreSQL,会要求输入数据库用户密码。

diffsettings.py

我们在使用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文件,它提供给我们的是一个接口。可以实现解耦的作用。

dumpdata.py

此命令用于导出项目数据库中的数据
python manage.py dumpdata -o /home/b.json accounts.User --indent 2
-o 后面接输出文件路径
后边的accounts.User 是app名和model名
–indent 可以设置导出的格式。

flush

此命令可以清空数据库中所有数据,留下空表

inspectdb

Django用来反向生成Model的方法。此命令可以把配置中连接的数据库中的数据表,反向生成在指定app下的model中。
python manage.py inspecdb > [your app name]\models.py

loaddata

主要用于单元测试时测试数据的导入。

makemessages

国际化命令,见上compilemessages命令。

makemigrations

python manage.py makemigrations这个命令是记录我们对models.py的所有改动,并且将这个改动迁移到migrations这个文件下生成一个文件例如:0001文件。

migrate

此命令是把执行makemigrations之后所记录的改动,执行到数据库。

runserver

开发测试时常用到的,用来在本地通过Django内置服务器启动项目。

sendtestemail

发送测试邮件,验证配置中的邮箱是否有效。

shell

python manage shell 命令,将自动帮你处理DJANGO_SETTINGS_MODULE。这样在命令行中,即可直接对项目进行操作无需在配置环境变量。

showmigrations

执行python manage showmigrations 命令,将在终端看到当前项目可以获得的所有迁移信息。

sqlflush

打印出将数据库中的所有表返回到刚安装后的状态所需的SQL语句列表。即如何实现的flush命令。

sqlmigrate

打印出 migration 所需执行的sql语句。

sqlsequencereset

打印用于顺序重置给定应用程序名称的SQL语句。

squashmigration

压缩合并迁移文件

startapp

新建一个app。

startproject

新建一个项目。

test

用来测试项目模块功能。命令行中需输入要测试的功能模块
python manage.py test …

testserver

启用一个测试开发服务,命令行输入fixture路径来提供需要用到数据。

总结

core.management 是管理Django命令的模块。其中包含的内置命令是用来快速搭建项目并为开发者提供一些便捷的开发测试环境。
在准备使用这一模块建立属于自己的命令或者想对源码有深入的理解,需要提前熟悉以下Python库:
argparse,concurrent.futures。
整个management模块简单理解其实就是基于argparse库的二次开发。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/493074.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Gator Cloud】架构篇 - 提供基于云原生的数据安全保护

随着云计算的成熟和云计算系统的广泛使用,越来越多的企业选择将新业务部署到云上。但是,上云并不意味着就能够充分利用云平台的优势。目前,大部分的云化应用,依然还是基于传统的软件架构来搭建的,仅仅是移植到云上去运…

【python脚本系列】python脚本2——PDF转word文档

只需2行代码,轻松将PDF转换成Word 机器学习算法那些事 2023-05-05 18:58 发表于广东 编辑:数据分析与统计学之美 可将 PDF 转换成 docx 文件的 Python 库。该项目通过 PyMuPDF 库提取 PDF 文件中的数据,然后采用 python-docx 库解析内容的布局…

【面试题】关于JavaScript实现继承的六大方案,你都了解过吗?

​ 大厂面试题分享 面试题库 前后端面试题库 (面试必备) 推荐:★★★★★ 地址:前端面试题库 web前端面试题库 VS java后端面试题库大全 前言 面试官:“你说说 JavaScript 中实现继承有哪几种方法?” …

相交链表 给你两个单链表的头节点 headA 和 headB ,请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点,返回 null 。

题目 解析 题目要求 如果相交 就返回交点如果不相交 就返回NULL 思路 1.通过题目的描述我们可以知道,两个单链表相交只有一种形式 并不存在下面的的形式 我们已经明确了单链表相交的形式, 那我们要如何判断两个单链表相交呢 这里给出一种做法&…

Mysql安装5分钟解决

文章目录 1.下载安装包:2.MySQL的初始配置3.安装mysql的服务:4.初始化MySQL命令:5.开启mysql服务命令:6.登录验证:7.修改密码: 1.下载安装包: 直接通过这里安装MYSQL5.7下载链接 或者进入MySQL…

干翻Mybatis源码系列之第七篇:Mybatis提供的集成缓存方案

第一章:Mybatis Orm的缓存 Mybatis定义了一个对象缓存,是Mybatis对缓存的封装,为了屏蔽实现的差异,这被定义成了一个接口Interface,这样的话,Mybatis的缓存基本上是存储于JVM内存中的。 一:Ca…

信息技术服务知识笔记

一、运维 1、基础环境运维服务 对保证信息系统正常运行所必需的电力、空调、消防、安防等基础环境的运维。包括:机房电力、消防、安防等系统的理性检查及状态监控、相应支持、故障处理、性能优化等服务 2、硬件运维服务 对硬件设备(网络、主机、存储…

6.2.1mnist _eval

之前在调试6.2.1mnist _eval代码的时候,出现了下面的错误 //下面不阐述本人遇到的错误,直接告诉大家解决办法(以老师给的源代码进行演示) 首先,打开第6章的源代码 //点击程序与数据拆分的文件夹, 并将三个…

3、Flutter项目搭建

一、搭建项目 1.1 搭建空壳项目 接上篇的项目搭建、本篇将继续搭建各个界面.当BottomNavigationBar搭建起来后,在各个界面,没有显示对应的元素,因此我们在包含它的Scaffold中,添加body,这样让每个界面撑起来.每次点击就切换对应的界面. 那么我们创建一个_RootPageState中的私…

【Python】scikit-plot可视化模型(含源代码)

文章目录 一、前言二、功能1:评估指标可视化2.1 scikitplot.metrics.plot_confusion_matrix2.2 scikitplot.metrics.plot_roc2.3 scikitplot.metrics.plot_ks_statistic2.4 scikitplot.metrics.plot_precision_recall2.5 scikitplot.metrics.plot_silhouette2.6 sci…

操作系统学习01

1、什么是操作系统? 通过以下四点可以概括操作系统到底是什么: 操作系统(Operating System,简称 OS)是管理计算机硬件与软件资源的程序,是计算机的基石。操作系统本质上是一个运行在计算机上的软件程序 &a…

微前端 qiankun@2.10.5 源码分析(一)

微前端 qiankun2.10.5 源码分析(一) 前言 微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略。 Techniques, strategies and recipes for building a modern web app with multiple teams that can ship feat…

Figma转换为sketch,分享这3款工具

在我们的设计工作中,我们经常会遇到各种各样的设计文件相互转换的问题。 你经常为此头疼吗?当你遇到Figma转换Sketch文件的问题时,你是如何解决的?Figma转换Sketch文件有工具吗? 根据众多设计师的经验,本…

在竞争激烈的移动应用市场中获得成功,掌握决胜Framework技术

为何要学习framework? Framework,指的是对应用程序开发所需的核心工具和组件的封装和提供。在Android开发中,Framework是整个开发过程中的核心组成部分,提供了许多功能和服务,包括UI组件、数据存储、网络通信、多媒体…

第二十四章 策略模式

文章目录 前言传统方式解决鸭子问题完整代码抽象鸭子类野鸭子类北京鸭子类玩具鸭子类 一、策略模式基本介绍二、策略模式解决鸭子问题完整代码飞翔接口 FlyBehavior飞翔接口的子类实现飞翔技术高超 GoodFlyBehavior不会飞翔 NoFlyBehavior飞翔技术一般 BadFlyBehavior其他行为接…

文献阅读 Meta-SR: A Magnification-Arbitrary Network for Super-Resolution

题目 Meta-SR: A Magnification-Arbitrary Network for Super-Resolution Meta-SR: 用于超分辨率的任何放大网络 摘要 由于DCNN的发展,最近关于超分辨率的研究取得了巨大成功。然而,任意比例因子的超分辨率长期以来一直被忽视。以往的研究者大多将不同…

Stable-Diffusion AI画画本地搭建详细步骤

ChatGPT出来后,第一次感觉到人工智能真的可能要来了,因此也顺便尝试了下开源AI画画的搭建。网络上写的教程总是不那么面面俱到,因此本文参考了3篇文章才成功把Stable-Diffusion 本地搭建搭建了起来。参考教程在文末。 本文是本地搭建AI画画&a…

C/C++内存泄露检查利器—valgrind

1、Valgrind概述 Valgrind是一套Linux下,开放源代码(GPL V2)的仿真调试工具的集合。 Valgrind由内核(core)以及基于内核的其他调试工具组成。内核类似于一个框架(framework),它模拟…

Android中的GPS开发

GPS简介 Gobal Positioning System,全球定位系统,是美国在20世纪70年代研制的一种以人造地球卫星为基础的高精度无线电导航的定位系统,它在全球任何地方以及近地空间都能够提供准确的地理位置、车行速度及精确的时间信息;它是具有…

2023年房地产抵押贷款研究报告

第一章 概述 房地产抵押贷款是一种以房地产为抵押品的贷款形式,包括个人和企业两种情况。个人房地产抵押贷款是指个人将名下房产作为抵押品向银行或其他金融机构申请贷款,而企业房地产抵押贷款则是指企业将自己名下的商业房产作为抵押品向金融机构申请贷…