源码分析
1、导入settings文件的方式是
from django.conf import settings
2、点进settings文件中
# 发现settings是LazySettings的实例化对象
settings = LazySettings()
3、点击LazySettings到类的定义中
class LazySettings(LazyObject):
def _setup(self, name=None):
# os.environ 相当于是一个全局的字典,只要在项目当中通过os.environ都可以拿到这个字典,这里是从这个字典中取一个ENVIRONMENT_VARIABLE
settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
if not settings_module:
... ...
4、点击ENVIRONMENT_VARIABLE进去看取得到底是什么值
ENVIRONMENT_VARIABLE = "DJANGO_SETTINGS_MODULE"
看到这里得出是想从全局拿一个DJANGO_SETTINGS_MODULE的值,但是这个值在什么时候设置的呢,Django一旦启动肯定回查找settings文件,而Django的启动文件又是 manage.py,所以可以去 manage.py 中找找。
5、在 manage.py 中有这一句,相当于是字典的赋值,而这里的值就是项目中我们可以进行配置的settings文件的路径。
# 相当于 os.environ["DJANGO_SETTINGS_MODULE"] = "MyCode.settings"
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "MyCode.settings")
6、拿到了这个值后回到第三步LazySettings类中,
def _setup(self, name=None):
settings_module = os.environ.get(ENVIRONMENT_VARIABLE)
... ...
# 这里又实例化了一个对象,并且把拿到的settings_module传了进去,及"MyCode.settings"被传进去了
self._wrapped = Settings(settings_module)
7、点进Settings中看上面对象的实例化过程
from django.conf import global_settings
... ...
class Settings(object):
def __init__(self, settings_module):
# 这里有一个global_settings,在最上面可以发现它的导入过程
for setting in dir(global_settings):
if setting.isupper():
... ...
8、点进global_settings中可以发现,这个配置文件是Django系统默认的配置文件,所有的配置都在这里面。
from __future__ import unicode_literals
def gettext_noop(s):
return s
####################
# CORE #
####################
DEBUG = False
DEBUG_PROPAGATE_EXCEPTIONS = False
USE_ETAGS = False
... ...
9、回到第7步
def __init__(self, settings_module):
# dir是获取当前对象里面所有的名称空间的名字,及拿到了配置文件中所有的变量名
for setting in dir(global_settings):
# 判断循环到的变量名是不是大写
if setting.isupper():
# setting, getattr(global_settings, setting)配置文件中的所有的变量名和对应的值
setattr(self, setting, getattr(global_settings, setting))
# 把前面获取到的字符串"MyCode.settings"赋值给SETTINGS_MODULE
self.SETTINGS_MODULE = settings_module
# importlib.import_module将字符串变成from什么import什么,下面就变成了from MyCode import settings,及导入了项目中的配置文件
mod = importlib.import_module(self.SETTINGS_MODULE)
... ...
# 拿到项目配置文件中变量名
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是项目的配置文件中的变量名,setting_value是项目的配置文件中的变量名对应的值,利用setattr如果变量在项目的配置文件中配置了就把对应的值赋给该变量,如果没有配置就使用系统的默认值
setattr(self, setting, setting_value)
self._explicit_settings.add(setting)
拓展:
importlib模块支持传入字符串来引入一个模块。importlib.import_module将字符串变成from什么import什么。
# 部分源码
def _find_and_load_unlocked(name, import_):
path = None
parent = name.rpartition('.')[0]
... ...