
3.1.2 LazySettings类
LazySettings类的定义如下:


上面的代码非常有意思,它展示了一种懒加载的代码模式。Settings类在实例化时会设置很多属性及属性值,LazySettings类则是在第一次访问该对象的某个属性时才去设置相应的属性及属性值。这种模式是如何做到的呢?实际上,在调用LazySettings类的某个属性时,会进入类的魔法函数__setattr__()中。该魔法函数先校验该对象的_wrapped属性,在第一次进入该魔法函数时,_wrapped属性值为空对象,即self._wrapped is empty语句为True,,于是调用_setup()方法。而_setup()方法会先从环境变量中读取settings_module的值,接着根据settings_module的值实例化Settings类,并赋给LazySettings对象的_wrapped属性。在这个赋值语句中,LazySettings类加载了settings_module和global_settings中的所有配置信息并保存在了_wrapped属性中。接下来在获取_wrapped属性值时,就不会加载所有的配置了,而是直接从_wrapped属性中获取。以下是对该类的一些操作示例:

上面的代码演示了LazySettings对象在第一次和后续调用属性时_wrapped属性值的区别。
在2.3节介绍shell命令的执行过程时曾遇到这个设置环境变量的语句,它出现在Django项目的manage.py文件中。下面是first_django项目的manage.py文件中的内容:


实际上,在manage.py文件中设置的环境变量正是用在配置变量读取上的,即这里的LazySettings类中。在__init__.py文件中还有一条非常关键的语句:

有了这条语句,LazySettings类的演示操作就非常简单了。这里将演示导入该对象并读取first_django项目中关于数据库的配置信息,这和后面要讲的内容息息相关:

这样即可读取settings.py文件中的配置信息了。至此,前文提出的两个问题就迎刃而解了。