start
As described in previous articles, you can also see some configuration references in Djangos configuration file Settings. Such as INSTALLED_APPS, MIDDLEWARE, and ROOT_URLCONF.
So how does this configuration module work?
start
This is generally recommended with reference to the Django configuration
from django.conf import settings
Copy the code
Rather than
from proj import settings
Copy the code
If you use the second form, Settings references other modules, which can cause circular references. In the first form, Django uses a lazy loading mechanism (loading only when needed).
Details can be viewed through the source code.
To understand
settings = LazySettings()
class LazySettings(LazyObject):
def _setup(self, name=None):
Extract the Settings module path from the environment variable
settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
self._wrapped = Settings(settings_module)
def __getattr__(self, name):
""" returns the set value and caches it in __dict__ """
if self._wrapped is empty:
self._setup(name)
val = getattr(self._wrapped, name)
self.__dict__[name] = val
return val
def __setattr__(self, name, value):
if name == '_wrapped':
self.__dict__.clear()
else:
self.__dict__.pop(name, None)
super().__setattr__(name, value)
... # omit other functions
Copy the code
Lazy loading is when you need it. Django implements this mechanism through the proxy class LazyObject. The loading function is _setup, which is loaded when a property is acquired and cached in the instance’s __dict__.
LazySettings inherits From LazyObject and overrides __setattr__ and __getattr__, assuming that the __getattr__ method implementation is called when the settings.DEBUG property is called.
From there, we can observe that all attributes are retrieved from the _wrapped (Settings(settings_module) instance) private attribute.
Configuration is loaded
We saw above that the path to the Settings module is extracted from the environment variable, and the _wrapped attribute points to an instance of the Settings class.
class Settings:
def __init__(self, settings_module):
Read the default configuration
for setting in dir(global_settings):
if setting.isupper():
setattr(self, setting, getattr(global_settings, setting))
# Config module
self.SETTINGS_MODULE = settings_module
# dynamic import
mod = importlib.import_module(self.SETTINGS_MODULE)
tuple_settings = (
"INSTALLED_APPS"."TEMPLATE_DIRS"."LOCALE_PATHS",
)
self._explicit_settings = set()
# Read properties under config module (may override some default configurations)
for setting in dir(mod):
if setting.isupper():
setting_value = getattr(mod, setting)
setattr(self, setting, setting_value)
self._explicit_settings.add(setting)
Copy the code
conclusion
If _wrapped is empty, the _setup method is called. This method gets the configuration file module internally. The _wrapped property points to an instance of the Settings class. When instantiated, the constructor reads global_settings to set some default properties, then loads the configuration module’s properties in the form of a dynamically imported module importlib.import_module, which reads the properties from _wrapped.