Django 加载settings配置

伍弘盛
2023-12-01

启动服务python manage.py runserver

配置文件settings.py, 设置DJANGO_SETTINGS_MODULE环境变量,调用django.setup()启动

import os, sys

def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'MyProject.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError("...") from exc
    execute_from_command_line(sys.argv)

if __name__ == '__main__':
    main()

django.setup()

def setup(set_prefix=True):
    """
    Configure the settings (this happens as a side effect of accessing the
    first setting), configure logging and populate the app registry.
    Set the thread-local urlresolvers script prefix if `set_prefix` is True.
    """
    from django.apps import apps
    from django.conf import settings
    from django.urls import set_script_prefix
    from django.utils.log import configure_logging

    configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
    if set_prefix:
        set_script_prefix(
            '/' if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME
        )
    apps.populate(settings.INSTALLED_APPS)

1. LazySettings 惰性加载配置

加载 DJANGO_SETTINGS_MODULE环境变量,初始化 django.conf.settings类

class LazySettings(LazyObject):
	def _setup(self, name=None):
        settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
        if not settings_module:
            desc = ("setting %s" % name) if name else "settings"
            raise ImproperlyConfigured("....")

        self._wrapped = Settings(settings_module)
    
    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

class Settings:
	def __init__(self, settings_module):
		pass   # 加载配置

2. 加载APP模块

根据settings.py文件中注册的INSTALLED_APPS列表,遍历各个App模块下的Models.

apps.populate(settings.INSTALLED_APPS)

延伸

1. Django LazyObject类

django中延迟加载,一个类只在第一次使用时才初始化。继承LazyObject的子类必须实现_setup()方法。

def new_method_proxy(func):
    def inner(self, *args):
        if self._wrapped is empty:
            self._setup()
        return func(self._wrapped, *args)
    return inner
    
    
class LazyObject:
	def __init__(self):
        # Note: if a subclass overrides __init__(), it will likely need to
        # override __copy__() and __deepcopy__() as well.
        self._wrapped = empty
        
	__getattr__ = new_method_proxy(getattr)
	
	def _setup(self):
	    """ Must be implemented by subclasses to initialize the wrapped object. """
        raise NotImplementedError('subclasses of LazyObject must provide a _setup() method')

如下,当第一次调用t.name时,先后调用 LazyObject.__getattr__LazyObject.new_method_proxy()self._setup()Test.__init__()getattr(self._wrapped, *args);之后再取值不会再调用self._setup()

from django.utils.functional import LazyObject

class Test(object):
    def __init__(self):
        self.name = 'Hello'
        
class LazyTest(LazyObject):
    def _setup(self):
        self._wrapped = Test()
 
t = LazyTest()  # 还没真正实例化
print(t.name)    # 触发加载 

2. Django lazy函数

Promiss代理类的基类,用于识别代码中需要惰性加载的对象。

from django.utils.functional import lazy

def lazy_func(text):  
    return text.title()

# 获得一个惰性代理对象lazy_wraper
lazy_wraper = lazy(lazy_func, str)
# 注意,此时虽然调用了惰性函数,但并不会直接去调用lazy_func函数
res = lazy_wraper('hello world')
# 打印结果时,才会去实际调用lazy_func。
print(res)  

参考文献

django源码分析之惰性加载(lazy和LazyObject)

 类似资料: