使用
应从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懒加载