django源码分析--03app加载过程
2017-09-10 00:00
531 查看
django.core.management.__init__.ManagementUtility.execute方法中通过
autoreload.check_errors(django.setup)()这一行代码来加载django的app。
django.__init__.setup方法中通过
django.apps.registry.Apps.populate(settings.INSTALLED_APPS)来加载所有配置文件中定义好的app。刚创建好的一个project默认模版都会在settings.py文件中指定好这几个app:
django.contrib.admin
django.contrib.auth
django.contrib.contenttypes
django.contrib.sessions
django.contrib.messages
django.contrib.staticfiles
django.apps.registry.Apps.populate方法中通过下面这个代码片段调用
django.apps.config.AppConfig.create的类方法来加载app和实例化该app的类对象。
django.apps.registry.py
from .config import AppConfig class Apps(object): def __init__(self, installed_apps=()): if installed_apps is None and hasattr(sys.modules[__name__], 'apps'): raise RuntimeError("You must supply an installed_apps argument.") self.all_models = defaultdict(OrderedDict) self.app_configs = OrderedDict() self.stored_app_configs = [] self.apps_ready = self.models_ready = self.ready = False self._lock = threading.Lock() self._pending_operations = defaultdict(list) if installed_apps is not None: self.populate(installed_apps) def populate(self, installed_apps=None): if self.ready: return with self._lock: if self.ready: return if self.app_configs: raise RuntimeError("populate() isn't reentrant") for entry in installed_apps: if isinstance(entry, AppConfig): app_config = entry else: # 这里这个for循环落实的工作是, # 实例化每个app的配置管理对象( # django.contrib.auth.apps.AuthConfig()), # 实例化过后默认有很多参数都是None, # 例如models_module、models等。 app_config = AppConfig.create(entry) if app_config.label in self.app_configs: raise ImproperlyConfigured( "Application labels aren't unique, " "duplicates: %s" % app_config.label) self.app_configs[app_config.label] = app_config counts = Counter( app_config.name for app_config in self.app_configs.values()) duplicates = [ name for name, count in counts.most_common() if count > 1] if duplicates: raise ImproperlyConfigured( "Application names aren't unique, " "duplicates: %s" % ", ".join(duplicates)) self.apps_ready = True # Load models. for app_config in self.app_configs.values(): # 这里采用字典引用的方式赋值给all_models, # 也就是说后续self.all_models['django.contrib.auth'] # 发生变化,它也会发生变化。 all_models = self.all_models[app_config.label] # 这里采用了非常高级的做法,以我现在的水平, # 暂时还不能完全理解,但是我已经有一些眉目了, # 详细的说明请进入import_models方法中继续查看。 app_config.import_models(all_models) self.clear_cache() self.models_ready = True for app_config in self.get_app_configs(): # 这里是针对app进行检查是否已经存在, # 如果已经存在则不做事情,如果不存在则 # 将它添加到CheckRegistry.registered_checks和 # 将它添加到CheckRegistry.deployment_checks的 # 注册列表中。 # 备注: 维护这个列表的用意我暂时还不清楚。 app_config.ready() self.ready = True
django.apps.config.py
class AppConfig(object): def __init__(self, app_name, app_module): self.name = app_name self.module = app_module @classmethod def create(cls, entry): try: # entry = 'django.contrib.auth' , module = <module 'django.contrib.auth' from 'C:\\Python35\\lib\\site-packages\\django\\contrib\\auth\\__init__.py'> module = import_module(entry) except ImportError: module = None mod_path, _, cls_name = entry.rpartition('.') if not mod_path: raise else: try: # entry = 'django.contrib.auth.apps.AuthConfig' entry = module.default_app_config except AttributeError: return cls(entry, module) else: # mod_path = 'django.contrib.auth.apps', # _ = '.' , # cls_name = 'AuthConfig' mod_path, _, cls_name = entry.rpartition('.') # mod = <module 'django.contrib.auth.apps' from 'C:\\Python35\\lib\\site-packages\\django\\contrib\\auth\\apps.py'> mod = import_module(mod_path) try: # cls = <class django.contrib.auth.apps.AuthConfig> cls = getattr(mod, cls_name) except AttributeError: if module is None: import_module(entry) else: raise if not issubclass(cls, AppConfig): raise ImproperlyConfigured( "'%s' isn't a subclass of AppConfig." % entry) try: # app_name = cls.name = 'django.contrib.auth' app_name = cls.name except AttributeError: raise ImproperlyConfigured( "'%s' must supply a name attribute." % entry) # app_module = <module 'django.contrib.auth' from 'C:\\Python35\\lib\\site-packages\\django\\contrib\\auth\\__init__.py'> app_module = import_module(app_name) # <AuthConfig: auth> = <django.contrib.auth.apps.AuthConfig object app_name='django.contrib.auth' app_module='<module 'django.contrib.auth' from 'C:\\Python35\\lib\\site-packages\\django\\contrib\\auth\\__init__.py'>' at 0x000001E02D9AE470> return cls(app_name, app_module) def import_models(self, all_models): self.models = all_models if module_has_submodule(self.module, MODELS_MODULE_NAME): # self.name = app_name = 'django.contrib.auth' , MODELS_MODULE_NAME = 'models' ; models_module_name = 'django.contrib.auth.models' models_module_name = '%s.%s' % (self.name, MODELS_MODULE_NAME) # 这里将'django.contrib.auth.models'整个文件模块形式的导入到self.models_module变量中. # 但是由于'django.contrib.auth.models'的class中有继承ModelBase,然后ModelBase.__new__, # 在导入过程中会被触发并执行__new__下的代码块,该代码块中对 # apps.get_containing_app_config('django.contrib.auth')单独进行register_model(模型注册), # 因此它会再次更新self.all_models,然后all_models会跟着发生变化,然后这里的self.models也会跟着发生变化。 # 最终呈现出来的是: <django.contrib.auth.AppConfig object self.models=OrderedDict([('permission', <class 'django.contrib.auth.models.Permission'>), ('group_permissions', <class 'django.contrib.auth.models.Group_permissions'>), ('group', <class 'django.contrib.auth.models.Group'>), ('user_groups', <class 'django.contrib.auth.models.User_groups'>), ('user_user_permissions', <class 'django.contrib.auth.models.User_user_permissions'>), ('user', <class 'django.contrib.auth.models.User'>)]) at 0x000001E02D9AE470> # 通过呈现结果的对象来看,self.models已经装载了这些<已经加载好的数据库>对象。 self.models_module = import_module(models_module_name) # self.models_module = import_module(models_module_name) = import_module('django.contrib.auth.models')
总结
django在启动wsgi之前,会调用django.apps模块来读取项目文件中的settings.py拿到这面这几个app,然后交给django.apps的registry.py和config.py来进行统一的配置加载、实例化(含models数据库对象)。
相关文章推荐
- Android 4.0 Launcher2源码分析——Launcher内容加载详细过程
- mybatis源码学习之执行过程分析(0)——配置文件加载(io包)
- Android 4.0 Launcher2源码分析——Launcher内容加载详细过程
- 分析Java的类加载器与ClassLoader(二):classpath与查找类字节码的顺序,分析ExtClassLoader与AppClassLoader的源码
- 【Spring源码分析系列】启动component-scan类扫描加载过程
- java虚拟机类加载过程内存情况底层源码分析及ClassLoader讲解
- spring启动component-scan类扫描加载过程---源码分析
- 黑马程序员--05.类加载器--03【从JVM加载类的过程再看类加载器】【从Java源码再看双亲委派模型】
- spring启动component-scan类扫描加载过程---源码分析
- 【spring源码分析】加载bean过程(2)
- Android 4.0 Launcher2源码分析——Launcher内容加载详细过程
- Android App启动时Apk资源加载机制源码分析
- spring源码分析 加载bean过程
- Android App启动时Apk资源加载机制源码分析
- Android OpenGL库加载过程源码分析
- Activity View加载过程-源码分析
- 源码分析微信热修复框架Tinker的类加载过程
- 深入理解 spring 容器,源码分析加载过程
- 源码分析之应用加载过程解析AndroidManifest
- Android硬件抽象Hardware库加载过程源码分析