zoukankan      html  css  js  c++  java
  • django基本执行启动过程的源码简单分析和settings.py分环境配置

    1. 从django的配置文件加载说开去

    我们在运行django的项目时,除了工程化的线上环境部署的时候,会利用supervisord或者gunicorn进行运行,在开发环境大多数会用命令行进行执行
    python manage.py runserver 0:8080
    如果需要指定settings文件,会这样运行
    python manage.py runserver 0:8080 --settings=ldaptest.settings-prd
    就能让django加载我们在settings.prd.py这个文件里定义的配置,这是怎么做到的呢

    1. django项目的简单执行流程

    python manage.py runserver 0:8080 --settings=ldaptest.settings-prd 是怎么执行的呢?
    我们看看manage.py的源码

    #!/usr/bin/env python
    import os
    import sys
    
    if __name__ == "__main__":
        os.environ.setdefault("DJANGO_SETTINGS_MODULE", "ldaptest.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)
    

    我们可以看到,实际执行的是execute_from_command_line方法,我们继续跟到这个函数

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

    可以看到,执行的是ManagementUtility的execute方法,我们继续跟到这个方法
    看下代码片段:

    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:])
    	print 'args:'    #增加调试
    	print options, args #增加调试
    	handle_default_options(options)
    except CommandError:
    	pass  # Ignore any option errors at this point.
    
    try:    
    	settings.INSTALLED_APPS
    except ImproperlyConfigured as exc: 
    	self.settings_exception = exc
    
    

    我们增加几行调试语句
    其实这个打印的就是我们传入的命令行参数
    我们执行 python manage.py runserver 0:8080 --settings=1
    可以看到报错如下

    执行结果

    可以看到,打印出了settings=1
    我们继续跟代码,一层层往下跟,直到跟到异常抛出的地方
    这个代码位于 django/conf/init.py

    import importlib
    import os
    import time
    
    from django.conf import global_settings
    from django.core.exceptions import ImproperlyConfigured
    from django.utils.functional import LazyObject, empty
    
    ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
    class Settings(object):
        def __init__(self, settings_module):
            # update this dict from global settings (but only for ALL_CAPS settings)
            for setting in dir(global_settings):
                if setting.isupper():
                    setattr(self, setting, getattr(global_settings, setting))
    
            # store the settings module in case someone later cares
            self.SETTINGS_MODULE = settings_module
    
            mod = importlib.import_module(self.SETTINGS_MODULE)
    
            tuple_settings = (
                "INSTALLED_APPS",
                "TEMPLATE_DIRS",
                "LOCALE_PATHS",
            )
            self._explicit_settings = set()
            for setting in dir(mod):
                if setting.isupper():
                    setting_value = getattr(mod, setting)
    
                    if (setting in tuple_settings and
                            not isinstance(setting_value, (list, tuple))):
                        raise ImproperlyConfigured("The %s setting must be a list or a tuple. " % setting)
                    setattr(self, setting, setting_value)
                    self._explicit_settings.add(setting)
    
            if not self.SECRET_KEY:
                raise ImproperlyConfigured("The SECRET_KEY setting must not be empty.")
    
            if hasattr(time, 'tzset') and self.TIME_ZONE:
                # When we can, attempt to validate the timezone. If we can't find
                # this file, no check happens and it's harmless.
                zoneinfo_root = '/usr/share/zoneinfo'
                if (os.path.exists(zoneinfo_root) and not
                        os.path.exists(os.path.join(zoneinfo_root, *(self.TIME_ZONE.split('/'))))):
                    raise ValueError("Incorrect timezone setting: %s" % self.TIME_ZONE)
                # Move the time zone info into os.environ. See ticket #2315 for why
                # we don't do this unconditionally (breaks Windows).
                os.environ['TZ'] = self.TIME_ZONE
                time.tzset()
    
        def is_overridden(self, setting):
            return setting in self._explicit_settings
    
        def __repr__(self):
            return '<%(cls)s "%(settings_module)s">' % {
                'cls': self.__class__.__name__,
                'settings_module': self.SETTINGS_MODULE,
            }
    
    

    可以看看这个代码都干了啥?
    这个类的初始化部分,利用dir方法把django/conf/global_setting.py这个即这个类前面导入部分的
    from django.conf import global_setting
    用dir方法把这个模块的各种属性全部列出来,并且只取列出的属性中属性是大写的部分,并利用getattr和setattr把这些设置成Settings这个类的属性

    这就是我们为什么可以利用变量定义一些程序中可能会用到的属性k-v值
    比如,在settings.py里定义 mysqladdr = 1.2.3.4
    则在程序里可以使用

    from django.conf import settings

    mysql_conn = settings.mysqladdr

    则在程序里可以像上面这样使用的原因就在这了

  • 相关阅读:
    代码转换为html显示
    subprocess实时获取结果和捕获错误
    centos7开放端口和防火墙设置
    Inside The C++ Object Model(一)
    知其所以然(以算法学习为例)
    sql语法
    DLL断点调试
    我的算法学习之路
    算法系列之一
    cocos2d-x游戏引擎核心(3.x)----事件分发机制之事件从(android,ios,desktop)系统传到cocos2dx的过程浅析
  • 原文地址:https://www.cnblogs.com/haozike/p/django-manange_py.html
Copyright © 2011-2022 走看看