【26.0】Django框架之settings源码

【一】Django配置文件介绍

  • Django框架默认提供给我们一个配置文件
  • 在我们项目根目录下的 setting.py 文件中,在里面我们可以看到很多的配置项
  • 并且我们能够自主的添加相应的配置
  • 但是其实这个文件只是Django暴露出来给我们的一个接口文件,在Django内部还存在一个更加强大的配置文件
# Django项目暴露出来,我们可以自主修改的配置文件
from 项目名 import settings

# Django内置的配置文件(用户不指定的前提下,使用默认的配置)
from django.conf import settings

【二】配置文件的优先级

  • 当我们不对配置文件进行额外的配置修改时,项目会使用默认的配置文件
  • 当我们在自定义的配置文件中修改了相关配置后,项目就会使用自定义的配置
# 比如 在项目目录下的配置文件中有一个配置项
# 这个配置的配置项含义是,当前项目所使用的语言为英文
# 在Django的后台登录上游很好的展现,我们看到的提示信息都是英文的
LANGUAGE_CODE = 'en-us'
# 但是其实在Django的默认配置文件中我们可以看到这个配置项还有很多其他的选择
# from django.conf.settings import global_settings

LANGUAGE_CODE = 'en-us'

# Language code for this installation. All choices can be found here:
# http://www.i18nguy.com/unicode/language-identifiers.html
# Languages we provide translations for, out of the box.
LANGUAGES = [
    ('af', gettext_noop('Afrikaans')),
    ('ar', gettext_noop('Arabic')),
    ('ar-dz', gettext_noop('Algerian Arabic')),
    ('ast', gettext_noop('Asturian')),
    ('az', gettext_noop('Azerbaijani')),
    ('bg', gettext_noop('Bulgarian')),
    ('be', gettext_noop('Belarusian')),
    ('bn', gettext_noop('Bengali')),
    ('br', gettext_noop('Breton')),
    ('bs', gettext_noop('Bosnian')),
    ('ca', gettext_noop('Catalan')),
    ('cs', gettext_noop('Czech')),
    ('cy', gettext_noop('Welsh')),
    ('da', gettext_noop('Danish')),
    ('de', gettext_noop('German')),
    ('dsb', gettext_noop('Lower Sorbian')),
    ('el', gettext_noop('Greek')),
    ('en', gettext_noop('English')),
    ('en-au', gettext_noop('Australian English')),
    ('en-gb', gettext_noop('British English')),
    ('eo', gettext_noop('Esperanto')),
    ('es', gettext_noop('Spanish')),
    ('es-ar', gettext_noop('Argentinian Spanish')),
    ('es-co', gettext_noop('Colombian Spanish')),
    ('es-mx', gettext_noop('Mexican Spanish')),
    ('es-ni', gettext_noop('Nicaraguan Spanish')),
    ('es-ve', gettext_noop('Venezuelan Spanish')),
    ('et', gettext_noop('Estonian')),
    ('eu', gettext_noop('Basque')),
    ('fa', gettext_noop('Persian')),
    ('fi', gettext_noop('Finnish')),
    ('fr', gettext_noop('French')),
    ('fy', gettext_noop('Frisian')),
    ('ga', gettext_noop('Irish')),
    ('gd', gettext_noop('Scottish Gaelic')),
    ('gl', gettext_noop('Galician')),
    ('he', gettext_noop('Hebrew')),
    ('hi', gettext_noop('Hindi')),
    ('hr', gettext_noop('Croatian')),
    ('hsb', gettext_noop('Upper Sorbian')),
    ('hu', gettext_noop('Hungarian')),
    ('hy', gettext_noop('Armenian')),
    ('ia', gettext_noop('Interlingua')),
    ('id', gettext_noop('Indonesian')),
    ('ig', gettext_noop('Igbo')),
    ('io', gettext_noop('Ido')),
    ('is', gettext_noop('Icelandic')),
    ('it', gettext_noop('Italian')),
    ('ja', gettext_noop('Japanese')),
    ('ka', gettext_noop('Georgian')),
    ('kab', gettext_noop('Kabyle')),
    ('kk', gettext_noop('Kazakh')),
    ('km', gettext_noop('Khmer')),
    ('kn', gettext_noop('Kannada')),
    ('ko', gettext_noop('Korean')),
    ('ky', gettext_noop('Kyrgyz')),
    ('lb', gettext_noop('Luxembourgish')),
    ('lt', gettext_noop('Lithuanian')),
    ('lv', gettext_noop('Latvian')),
    ('mk', gettext_noop('Macedonian')),
    ('ml', gettext_noop('Malayalam')),
    ('mn', gettext_noop('Mongolian')),
    ('mr', gettext_noop('Marathi')),
    ('my', gettext_noop('Burmese')),
    ('nb', gettext_noop('Norwegian Bokmål')),
    ('ne', gettext_noop('Nepali')),
    ('nl', gettext_noop('Dutch')),
    ('nn', gettext_noop('Norwegian Nynorsk')),
    ('os', gettext_noop('Ossetic')),
    ('pa', gettext_noop('Punjabi')),
    ('pl', gettext_noop('Polish')),
    ('pt', gettext_noop('Portuguese')),
    ('pt-br', gettext_noop('Brazilian Portuguese')),
    ('ro', gettext_noop('Romanian')),
    ('ru', gettext_noop('Russian')),
    ('sk', gettext_noop('Slovak')),
    ('sl', gettext_noop('Slovenian')),
    ('sq', gettext_noop('Albanian')),
    ('sr', gettext_noop('Serbian')),
    ('sr-latn', gettext_noop('Serbian Latin')),
    ('sv', gettext_noop('Swedish')),
    ('sw', gettext_noop('Swahili')),
    ('ta', gettext_noop('Tamil')),
    ('te', gettext_noop('Telugu')),
    ('tg', gettext_noop('Tajik')),
    ('th', gettext_noop('Thai')),
    ('tk', gettext_noop('Turkmen')),
    ('tr', gettext_noop('Turkish')),
    ('tt', gettext_noop('Tatar')),
    ('udm', gettext_noop('Udmurt')),
    ('uk', gettext_noop('Ukrainian')),
    ('ur', gettext_noop('Urdu')),
    ('uz', gettext_noop('Uzbek')),
    ('vi', gettext_noop('Vietnamese')),
    ('zh-hans', gettext_noop('Simplified Chinese')),
    ('zh-hant', gettext_noop('Traditional Chinese')),
]

# 我们可以将默认的 en-us 替换成 zh-hans
# 这样我们在看到Django的提示信息的时候就会发现变成了简体中文

【三】配置文件的包含关系

  • 在项目根目录下的配置文件存在的配置项,在项目的全局配置文件中肯定也有
  • 但是在项目的全局配置文件中有的配置项,项目根目录下的配置文件未必有

【四】正确的配置文件使用

# 我们如果在Django项目的其他位置想要试用Django的配置文件,最正确的导入方式应该是

from django.conf import settings

# 这样导入的配置文件我们既可以使用自定义的,也可以使用全局默认的配置

【五】settings源码剖析

【1】入口

  • 我们通过导入全局的配置文件,从全局的配置文件进入到源码中
from django.conf import settings

【2】settings其实是一个对象

  • 我们可以看到 在源码的最后一行是 settings = LazySettings()

  • 也就是说,我们当前使用的 settings 其实是 LazySettings 类产生的一个对象

【3】剖析LazySettings

  • 剖析源码时,我们应该只剖析我们想要的核心部分,而不是所有源码都进行解读
  • 如果把所有源码都解读一遍,只会让我们的精力大大消耗掉
class LazySettings(LazyObject):

    def _setup(self, name=None):
      	# 在这里我们可以看到 通过项目环境变量获取到了键为 ENVIRONMENT_VARIABLE 的值
        # os.environ : 当前项目的环境变量
        # ENVIRONMENT_VARIABLE : 在上面有 
        # ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
        # DJANGO_SETTINGS_MODULE 在哪里能看到呢?,其实就是在我们项目文件 manage.py 中
        # os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'BulletinBoardSystem.settings')
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        
        # 入股没有加载到配置文件就会抛出异常
        if not settings_module:
            desc = ("setting %s" % name) if name else "settings"
            raise ImproperlyConfigured(
                "Requested %s, but settings are not configured. "
                "You must either define the environment variable %s "
                "or call settings.configure() before accessing settings."
                % (desc, ENVIRONMENT_VARIABLE))
				# 将获取到的本地配置文件的路径传给 Settings 实例化得到一个对象
        self._wrapped = Settings(settings_module)
  • manage.py
"""Django's command-line utility for administrative tasks."""
import os
import sys


def main():
    """Run administrative tasks."""
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'BulletinBoardSystem.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        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?"
        ) from exc
    execute_from_command_line(sys.argv)


if __name__ == '__main__':
    main()

【4】剖析Settings

class Settings:
    def __init__(self, settings_module):
        # settings_module : 是本地的项目配置文件路径
        # settings_module : 项目名.settings.py
        
        # 获取全局配置文件中所有的变量名
        for setting in dir(global_settings):
          	# 校验变量名是否是全大写
            # 这也是为什么在配置文件中所有的配置变量名都是大写的原因
            if setting.isupper():
              	# 在配置文件变量名全大写的前提下,设置相应的属性
                # setting : 当前配置的变量名
                # getattr(global_settings, setting) : 在全局配置文件中反射出指定键对应的属性值
                setattr(self, setting, getattr(global_settings, setting))

        # 将当前项目根目录的配置文件地址添加到自己的属性中
        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)

【六】案例

【1】自定义配置文件

  • conf.settings.py
SOME_NAME = "some_name"
SOME_PASSWORD = "some_password"

【2】根配置文件

  • lib.conf.global_settings.py
GLOBAL_NAME = "base_name"
GLOBAL_PASSWORD = "base_password"
  • lib.__init__.py
import os
import importlib

# 包初始化文件

# 导入全局配置文件
from lib.conf import global_settings


# 导入跟录下的配置文件
class Settings(object):
    def __init__(self):
        # 【一】设置全局变量名和变量值
        # 【1】循环获取当前全局配置文件中所有的变量名
        for name in dir(global_settings):
            # 【2】判断变量名是否为大写
            if name.isupper():
                # 【3】设置全局变量名和变量值
                setattr(self, name, getattr(global_settings, name))

        # 【二】设置项目变量名和变量值
        # 【1】获取得到当前模块路径
        module_path = os.environ.get("PROJECT_MODAL_SETTINGS")
        # 【2】获取得到当前模块对象
        mod = importlib.import_module(module_path)
        # 【3】遍历获取变量名设置值
        for name in dir(mod):
            if name.isupper():
                setattr(self, name, getattr(mod, name))


settings = Settings()

【3】启动文件

  • start.py
import os
import sys

sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

if __name__ == '__main__':
    # 设置当前根目录下的环境变量路径
    os.environ.setdefault("PROJECT_MODAL_SETTINGS", "conf.settings")
    from lib.conf import settings

    print(settings.GLOBAL_NAME)
    print(settings.SOME_NAME)
posted @ 2024-04-07 18:29  Chimengmeng  阅读(52)  评论(0编辑  收藏  举报