文档章节

【Django源码浅析】-Django命令系统

Archer弓兵
 Archer弓兵
发布于 2017/04/09 18:38
字数 1248
阅读 64
收藏 0
点赞 0
评论 0

鉴于笔者水平有限,文中不免出现一些错误,还请多多指教!

好了,下边是正文....

首先大概看一下Django 项目的主要目录,初步建立一下Django源码的世界观。

├── django          //工程代码存放路径
├── docs            //文档
├── extras          
├── js_tests        //测试
├── scripts         //脚本
└── tests           //单元测试

Django核心代码主要在django目录下边

django/
├── apps(app模块)
├── bin(可执行命令)
├── conf(配置)
├── contrib(其他开发者贡献代码)
├── core(核心组件)
├── db(ORM模块)
├── dispatch
├── forms(表单模块)
├── http
├── middleware(中间件)
├── template(模板)
├── templatetags
├── test(测试代码)
├── urls(url路由模块)
├── utils(工具代码)
└── views(视图模块)

在django中我们常用的命令主要有两个,一个是django-admin,一个是xxxx,我们先看一下django-admin

1、命令位置

lion@localhost:~/django/django$ whereis django-admin
django-admin: /usr/local/bin/django-admin /usr/local/bin/django-admin.py /usr/local/bin/django-admin.pyc

2、命令内容

lion@localhost:~/django/django$ cat /usr/local/bin/django-admin
#!/usr/bin/python

# -*- 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())

其实对比不难发现,django-admin命令其实对应的是django源码中的.django/bin/django-admin.py这个文件。

django-admin.py 引用了django.core中的management,并调用了其execute_from_command_line函数。

注:在最新版中django-admin和manage.py中调用的都是execute_from_command_line函数了,较旧版本的django中可能不同。

所以要分析django的命令系统,就要从execute_from_command_line函数入手。

execute_from_command_line函数定义:

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

函数初始化ManagementUtility类,传入argv(也就是命令行参数)参数,并执行execute方法

execute方法:

def execute(self):
    """
    Given the command-line arguments, this figures out which subcommand is
    being run, creates a parser appropriate to that command, and runs it.
    """
    try:
        subcommand = self.argv[1]
    except IndexError:
        subcommand = 'help'  # Display help if no arguments were given.

    # Preprocess options to extract --settings and --pythonpath.
    # These options could affect the commands that are available, so they
    # must be processed early.
    parser = CommandParser(None, usage="%(prog)s subcommand [options] [args]", add_help=False)
    parser.add_argument('--settings')
    parser.add_argument('--pythonpath')
    parser.add_argument('args', nargs='*')  # catch-all
    try:
        options, args = parser.parse_known_args(self.argv[2:])
        handle_default_options(options)
    except CommandError:
        pass  # Ignore any option errors at this point.

    no_settings_commands = [
        'help', 'version', '--help', '--version', '-h',
        'startapp', 'startproject', 'compilemessages',
    ]

    try:
        settings.INSTALLED_APPS
    except ImproperlyConfigured as exc:
        self.settings_exception = exc
        # A handful of built-in management commands work without settings.
        # Load the default settings -- where INSTALLED_APPS is empty.
        if subcommand in no_settings_commands:
            settings.configure()

    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

        # In all other cases, django.setup() is required to succeed.
        else:
            django.setup()

    self.autocomplete()

    if subcommand == 'help':
        if '--commands' in args:
            sys.stdout.write(self.main_help_text(commands_only=True) + '\n')
        elif len(options.args) < 1:
            sys.stdout.write(self.main_help_text() + '\n')
        else:
            self.fetch_command(options.args[0]).print_help(self.prog_name, options.args[0])
    # Special-cases: We want 'django-admin --version' and
    # 'django-admin --help' to work, for backwards compatibility.
    elif subcommand == 'version' or self.argv[1:] == ['--version']:
        sys.stdout.write(django.get_version() + '\n')
    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)

此方法主要解析命令行参数,加载settings配置,如果setting配置成功则执行django.setup函数(此函数主要是加载App),最后一步调用的核心命令为fetch_command命令,并执行run_from_argv函数

先看一下fetch_command函数

def fetch_command(self, subcommand):
    """
    Tries to fetch the given subcommand, printing a message with the
    appropriate command called from the command line (usually
    "django-admin" or "manage.py") if it can't be found.
    """
    # Get commands outside of try block to prevent swallowing exceptions
    commands = get_commands()
    try:
        app_name = commands[subcommand]
    except KeyError:
        if os.environ.get('DJANGO_SETTINGS_MODULE'):
            # If `subcommand` is missing due to misconfigured settings, the
            # following line will retrigger an ImproperlyConfigured exception
            # (get_commands() swallows the original one) so the user is
            # informed about it.
            settings.INSTALLED_APPS
        else:
            sys.stderr.write("No Django settings specified.\n")
        sys.stderr.write(
            "Unknown command: %r\nType '%s help' for usage.\n"
            % (subcommand, self.prog_name)
        )
        sys.exit(1)
    if isinstance(app_name, BaseCommand):
        # If the command is already loaded, use it directly.
        klass = app_name
    else:
        klass = load_command_class(app_name, subcommand)
    return klass

这个fetch_command函数类似一个工厂函数,由get_commands函数扫描出所有的子命令,包括managemen中的子命令和app下的managemen中commands的子命令(自定义),然后根据传入的subcommand初始化Command类。

如果子命令不在commands字典内的话,会抛出一个“Unknown command”的提示,如果子命令存在则返回初始化的Command类。

接着视角在返回到execute函数中,接着

self.fetch_command(subcommand).run_from_argv(self.argv)

将会调用fetch_command(subcommand)初始化Command类的run_from_argv方法。run_from_argv由各个Command的基类BaseCommand定义,最终将会调用各个子类实现的handle方法。从而执行子命令的业务逻辑。

至此,命令调用的逻辑基本完成。

 

笔者随笔:

通过阅读这一部分的代码,其中最值得学习的地方在于fetch_commands函数,这是一个运用工厂方法的最佳实践,这样不但最大程度的解耦了代码实现,同时使得命令系统更易于扩展(App 自定义子命令就是一个很好的说明)

再有一点就是Command基类的定义,对于各种子命令的定义,基类完整的抽象出了command业务的工作逻辑,提供了统一的命令调用接口使得命令系统更易于扩展。

 

© 著作权归作者所有

共有 人打赏支持
Archer弓兵
粉丝 5
博文 34
码字总数 14928
作品 0
杭州
程序员
Django1.8 django-admin和manage命令简要分析

startproject和startapp 创建一个项目(Project) Django使用django-admin startproject [projectname]命令生成project。 django-admin命令行的路径为:django/bin/django-admin.py 以djang......

donhui ⋅ 2015/11/23 ⋅ 3

PYTHON资源入口汇总

官网 入口 官方文档 英文 document 2.7.6 入口| 标准库 document 3.x 入口 The Hitchhiker’s Guide to Python 入口 Python Monk 入口 中文 document 2.7 入口 非官方 google的python文档 Go...

好铁 ⋅ 2016/02/12 ⋅ 0

Django学习笔记(一)

Django是python web框架中的一种,下面我就介绍一些自己在学习过程中遇到的问题。 官方网站:https://www.djangoproject.com,这个是我们在学习过程中需要重点参考的文档,而且我们需要经常翻...

彩虹的夜晚 ⋅ 2017/10/20 ⋅ 0

CentOS 6.4下安装Django

Django是一个基于python的网站开发框架,笔者学过了python的基本知识,对用python进行网站开发颇有兴趣。于是想安装一个在本地研究一下。 笔者本地操作系统是:CentOS 6.4,Linux内核:2.6.3...

临峰不畏 ⋅ 2014/06/08 ⋅ 0

Django 链接MySQL

Python版本:3.5.1 Django版本:1.9 前面将Python升级完,然后将pip安装,然后是安装Django,高高兴兴的使用命令: django-admin.py startproject first 把Django名为first的项目也建立了,然...

Edenwy ⋅ 2017/06/13 ⋅ 0

Django - 如何集成使用sitetree插件

问题背景: 在使用Metronic作为前端模版的时候, 默认的左侧导航栏的效果如下图所示: Metronic 左侧导航栏 其示例Html文件对于这一个导航栏的实现长达1000多行,此处只截取部分展示: 这段代...

fall4u ⋅ 2017/12/24 ⋅ 0

Centos Django+ Mod_wsgi

本文介绍了在Centos系统下搭建Django站点的流程。 一.安装环境 本文适合环境: centOS 5/6 python2.7+- Django1.5 mod_wsgi apache2.2/2.4 其中由于modpython对python2.7没有提供支持,因此采...

拜仁慕尼黑 ⋅ 2013/06/14 ⋅ 7

caravel之架构与源码浅析

如果你打算改造和定制caravel,这篇文章可能对你有帮助 外围观察 上边的这张图列出了caravel用到的部分技术(由Wappalyzer分析得出) 包括: 后端 采用python的Flask框架(当前版本是Flask 0...

aibati2008 ⋅ 2016/10/11 ⋅ 0

Django打造文件分享系统

本教程介绍如何使用Django框架快速打造文件分享系统,实现搜索功能,分享功能,用户分享文件查询。通过本课程,我们可以快速掌握Django的基础,以及一些ORM和View的高级用法。本课程适用于有...

实验楼 ⋅ 2017/12/22 ⋅ 0

Django学习记录-1

作为Django的初学者,记录下我的学习历程,加深一下记忆(工作中用java,所以很容易忘记),如果有写的不对的地方,还望大家指出,在此多谢了! 一:Django的安装: 我的操作系统环境是:win...

无悔这一生 ⋅ 2013/01/15 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

线程池

一、线程池:提供了一个线程队列,队列中保存着所有等待状态的线程。避免了创建与销毁额外开销,提高了响应的速度。 二、线程池的体系结构: java.util.concurrent.Executor : 负责线程的使用...

stars永恒 ⋅ 26分钟前 ⋅ 0

你值5K还是15K?实战案例,测测你的分析功力

本文源自陈老师遇到的真实案例。 老板说:“我们今年准备参加展会,做一年。以前我没参加过,没关系,这里有一份展会数据,你回去分析下哪些有价值,后边组织的时候有个指导”。现在你收到任...

加米谷大数据 ⋅ 27分钟前 ⋅ 0

中文转英文功能

package com.sysware.task.util;import net.sourceforge.pinyin4j.PinyinHelper;import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;import net.sourceforge.pinyin4j.for......

AK灬 ⋅ 28分钟前 ⋅ 0

JNI Java层类关联C/C++层的类

Android开发时,因为要实现某某功能,需要集成算法公司的算法库(so库),这就需要自己编写JNI。 通常这些库提供的接口可以概况成1、初始化 2、算法处理 3、释放 4、打印版本号 初始化后会返...

国仔饼 ⋅ 32分钟前 ⋅ 0

maven下载jar包改为阿里云的maven库

一:修改maven安装路径中conf文件夹下的setting.xml文件 <mirrors> <mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/......

夜醒者 ⋅ 32分钟前 ⋅ 0

电商用户行为分析大数据平台相关系列10-基础数据结构分析

电商用户行为分析大数据平台相关系列1-环境介绍 电商用户行为分析大数据平台相关系列2-HADOOP环境搭建 电商用户行为分析大数据平台相关系列3-HIVE安装 电商用户行为分析大数据平台相关系列4...

xiaomin0322 ⋅ 33分钟前 ⋅ 0

使用readLine()方法遇到的坑

下午玩 TCP/IP 的 Socket 通信时,使用 BufferedReader 的 readLine() 遇到了一个坑,现在终于解决了,特此记录下来。 程序很简单,客户段从控制台读取用户输入,然后发送至服务器端,主要代...

孟飞阳 ⋅ 33分钟前 ⋅ 0

基于Hadoop集群的Hive安装配置(Derby数据库)

Hive是一个数据仓库基础工具在Hadoop中用来处理结构化数据,提供简单的sql查询功能,可以将sql语句转换为MapReduce任务进行运行(具体的Hive架构大家自行搜索)。接下来主要讲下Hadoop集群下...

海岸线的曙光 ⋅ 34分钟前 ⋅ 0

CoreOS裸机iso安装和相关配置

裸机通过iso安装CoreOS,个人趟了很多坑,以下就是完整的从零开始部署和配置的过程,希望对大家有用。 一、安装CoreOS到硬盘 1. 准备Live iso镜像,制作好usb启动盘 Live iso下载地址 2. 搭建...

ykbj ⋅ 39分钟前 ⋅ 0

jquery控制表格锁列(转)

表格已经完成后新加的需求,要实现锁表格的第一列。很多带这种效果的都是js封装的框架或者具体某种框架的组件,不适用解决当前问题。作为后端开发又实在不熟样式,搜到了一个可以用的,虽然样...

刘昌鑫 ⋅ 41分钟前 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部