django 源码懒加载源码分析

Django源码解析:懒加载与INSTALLED_APPS
本文探讨了Django启动过程中settings.INSTALLED_APPS的工作原理。Django使用LazySettings确保属性在首次访问时才加载,通过设置模块加载工程属性,并允许工程设置覆盖默认属性。

在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中的属性可以覆盖掉默认属性即工程的设置。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值