在django启动过程中:
execute_from_command_line->utility.execute()->settings.INSTALLED_APPS
我们来看下settings.INSTALLED_APPS是如何工作的。
1、首先:
from django.conf import settings
我们查看settings,原来settings 是LazySettings的实例。
settings = LazySettings()
LazySettings继承了LazyObject。
class LazySettings(LazyObject):
2、然后,我们看下settings = LazySettings()实例化做了什么,LazySettings本身没有__init__方法,也就是说直接使用了__init__方法。
_wrapped = None
def __init__(self):
# Note: if a subclass overrides __init__(), it will likely need to
# override __copy__() and __deepcopy__() as well.
self._wrapped = empty
这个实例化什么都没做。
3、settings.INSTALLED_APPS 调用settings的属性INSTALLED_APPS ,发生了什么呢?
# 这个是LazySettings的__getattr__方法
def __getattr__(self, name):
"""Return the value of a setting and cache it in self.__dict__."""
if self._wrapped is empty:
self._setup(name)
val = getattr(self._wrapped, name)
self.__dict__[name] = val
return val
我们知道self._wrappe在初始化的时候是None,所以settings.INSTALLED_APPS会执行self._setup。
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
def _setup(self, name=None):
settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
print('--settings_module:', settings_module)
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))
self._wrapped = Settings(settings_module)
在django启动的时候,也就是manage.py中有
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "your_project.settings")
所以, settings_module = os.environ.get(ENVIRONMENT_VARIABLE)就是我们的django的setting模块。
4、self._wrapped = Settings(settings_module)
from django.conf import global_settings
class Settings:
def __init__(self, settings_module):
for setting in dir(global_settings):
if setting.isupper():
# global_setting文件是django的默认全局变量所在
# 把django的默认全局变量设置为实例的属性
setattr(self, setting, getattr(global_settings, setting))
# store the settings module in case someone later cares
self.SETTINGS_MODULE = settings_module
# 导入project的setting
mod = importlib.import_module(self.SETTINGS_MODULE)
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)
# 把setting中的变量设置为实例的属性, 如果和默认的设置名相同,会覆盖默认设置。
setattr(self, setting, setting_value)
self._explicit_settings.add(setting)
在self._wrapped = Settings(settings_module) 我们才真正的看到工程的属性加载。
总结,django在启动的过程中并没有开始就先把属性设置好。而是在第一次调用了属性时才加载所有的属性。而且我们可以看到,setting中的属性可以覆盖掉默认属性即工程的设置。
Django源码解析:懒加载与INSTALLED_APPS
本文探讨了Django启动过程中settings.INSTALLED_APPS的工作原理。Django使用LazySettings确保属性在首次访问时才加载,通过设置模块加载工程属性,并允许工程设置覆盖默认属性。
1862

被折叠的 条评论
为什么被折叠?



