Django settings加载

使用

应从django模块引入配置:

from django.conf import settings

而不是直接从项目文件中引入

from proj import settings

直接从项目文件中引入会破坏app的独立性。比如我想要把proj项目中的支付模块pay_app分离出去,就要修改所有pay_app中直接从proj项目配置文件中引入配置的语句

注意,django.conf.settings不是一个模块,而是一个对象。 所以不可以单独导入每个配置项:

from django.conf.settings import DEBUG  # 这是错误的做法

指定配置文件

在Django启动时需要制定配置文件,也就是给环境变量DJANGO_SETTINGS_MODULE赋值

# 万物起源:manage.py
#!/usr/bin/env python
import os
import sys

if __name__ == "__main__":
    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "demo.settings")

LazySettings

from django.conf import settings

实际上是引入了LazySettings类的一个实例,这是一个单例模式,每次导入的settings都是同一个实例对象

# django/conf/__init__.py
class LazySettings(LazyObject):
    ...

settings = LazySettings()

LazySettings继承自LazyObject,它会以懒加载的机制去读取配置,获取某个属性的当下才会去加载

ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"


class LazySettings(LazyObject):
    def _setup(self, name=None):
        # 从环境变量DJANGO_SETTINGS_MODULE中获取配置文件位置
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        # 真正读取配置的对象是Settings的实例
        self._wrapped = Settings(settings_module)

    def __getattr__(self, name):
        # 实例化settings后,settings被访问前,settings._wrapped为空对象
        if self._wrapped is empty:
            # 访问settings的属性,即调用__getattr__时才回去加载配置
            self._setup(name)
        val = getattr(self._wrapped, name)
        # 访问对象的属性时会先在 __dict__ 中查找
        # 没有找到,才会去调用 __getattr__ 方法
        # 因此这里使用self.__dict__做了缓存
        self.__dict__[name] = val
        return val


empty = object()

class LazyObject(object):
    _wrapped = None

    def __init__(self):
        self._wrapped = empty

LazySettingss主要用于控制配置文件的来源,并实现了懒加载的机制,真正读取配置的对象是Settings的实例

Settings

from django.conf import global_settings

class Settings(object):
    def __init__(self, settings_module):
        # global_settings 中是Django的默认配置
        for setting in dir(global_settings):
            if setting.isupper():
                # 先加载Django的默认配置
                setattr(self, setting, getattr(global_settings, setting))

        self.SETTINGS_MODULE = settings_module
        # 载入项目配置
        mod = importlib.import_module(self.SETTINGS_MODULE)

        for setting in dir(mod):
            # 只会载入项目配置文件中全部大写的 KEY
            # 因此,如果选择用django.conf导入配置,配置的KEY必须要全部大写
            # 如果直接从配置文件导入就没有这个限制了
            if setting.isupper():
                setting_value = getattr(mod, setting)
                # 项目配置会覆盖Django的默认配置
                # 相当于 self.__dict__[setting] = setting_value
                setattr(self, setting, setting_value)

参考资料

配置 Django

Django源码笔记——settings加载

Django源码分析(七):settings懒加载

你可能感兴趣的:(Django settings加载)