#django包的__init__.py包含setup函数
def setup(): """ Configure the settings (this happens as a side effect of accessing the first setting), configure logging and populate the app registry. """ from django.apps import apps from django.conf import settings from django.utils.log import configure_logging configure_logging(settings.LOGGING_CONFIG, settings.LOGGING) apps.populate(settings.INSTALLED_APPS)#apps对象安装app def populate(self, installed_apps=None): """ Loads application configurations and models. This method imports each application module and then each model module. It is thread safe and idempotent, but not reentrant. """ if self.ready: return # populate() might be called by two threads in parallel on servers # that create threads before initializing the WSGI callable. with self._lock: if self.ready: return # app_config should be pristine, otherwise the code below won't # guarantee that the order matches the order in INSTALLED_APPS. if self.app_configs: raise RuntimeError("populate() isn't reentrant") # Load app configs and app modules. for entry in installed_apps: if isinstance(entry, AppConfig): app_config = entry else: app_config = AppConfig.create(entry)#创建一个AppConfig对象 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 # Check for duplicate app names. counts = Counter( #判断有无重复的AppConfig对象对象 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():#为每个app导入models_module all_models = self.all_models[app_config.label] app_config.import_models(all_models) self.clear_cache() self.models_ready = True for app_config in self.get_app_configs(): app_config.ready() self.ready = True #以django.contrib.admin为例说明create过程 default_app_config = 'django.contrib.admin.apps.AdminConfig' class SimpleAdminConfig(AppConfig): """Simple AppConfig which does not do automatic discovery.""" name = 'django.contrib.admin' #作为app_name verbose_name = _("Administration") def ready(self): checks.register(check_admin_app, checks.Tags.admin) class AdminConfig(SimpleAdminConfig): """The default AppConfig for admin which does autodiscovery.""" def ready(self): super(AdminConfig, self).ready() self.module.autodiscover()
@classmethod #AppConfig类的创建方法 def create(cls, entry): """ Factory that creates an app config from an entry in INSTALLED_APPS. """ try: # If import_module succeeds, entry is a path to an app module, # which may specify an app config class with default_app_config. # Otherwise, entry is a path to an app config class or an error. module = import_module(entry)#会导入包的__init__.py except ImportError: # Track that importing as an app module failed. If importing as an # app config class fails too, we'll trigger the ImportError again. module = None mod_path, _, cls_name = entry.rpartition('.') # Raise the original exception when entry cannot be a path to an # app config class. if not mod_path: raise else: try: # If this works, the app module specifies an app config class. entry = module.default_app_config#从模块对象中取得默认配置文件类 except AttributeError: # Otherwise, it simply uses the default app config class. return cls(entry, module) else: mod_path, _, cls_name = entry.rpartition('.')#分解成路径和类名 # If we're reaching this point, we must attempt to load the app config # class located at <mod_path>.<cls_name> mod = import_module(mod_path)#导入apps模块 try: cls = getattr(mod, cls_name)#取得类对象,比如在admin中为AdminConfig except AttributeError: if module is None: # If importing as an app module failed, that error probably # contains the most informative traceback. Trigger it again. import_module(entry) else: raise # Check for obvious errors. (This check prevents duck typing, but # it could be removed if it became a problem in practice.) if not issubclass(cls, AppConfig): raise ImproperlyConfigured( "'%s' isn't a subclass of AppConfig." % entry) # Obtain app name here rather than in AppClass.__init__ to keep # all error checking for entries in INSTALLED_APPS in one place. try: app_name = cls.name#类对象中指定的name,比如name = 'django.contrib.admin'可以有'.'。 except AttributeError: raise ImproperlyConfigured( "'%s' must supply a name attribute." % entry) # Ensure app_name points to a valid module. app_module = import_module(app_name)#再次导入模块 # Entry is a path to an app config class. return cls(app_name, app_module)
现在的问题是什么时候导入models。