Django源码阅读(2)INSTALLED_APPS加载过程

  • 再次回到上节刚开始的 execute 函数,接下来我们就回过头来分析一下 django.setup() 函数,看看它里面是如何进行加载配置的 。
# django\core\management\__init__.py
def execute(self):
    ...
    if settings.configured:
        # Start the auto-reloading dev server even if the code is broken.
        # The hardcoded condition is a code smell but we can't rely on a
        # flag on the command class because we haven't located it yet.
        if subcommand == 'runserver' and '--noreload' not in self.argv:
            try:
                autoreload.check_errors(django.setup)()
            except Exception:
                # The exception will be raised later in the child process
                # started by the autoreloader. Pretend it didn't happen by
                # loading an empty list of applications.
                apps.all_models = defaultdict(OrderedDict)
                apps.app_configs = OrderedDict()
                apps.apps_ready = apps.models_ready = apps.ready = True

                # Remove options not compatible with the built-in runserver
                # (e.g. options for the contrib.staticfiles' runserver).
                # Changes here require manually testing as described in
                # #27522.
                _parser = self.fetch_command('runserver').create_parser('django', 'runserver')
                _options, _args = _parser.parse_known_args(self.argv[2:])
                for _arg in _args:
                    self.argv.remove(_arg)

        # In all other cases, django.setup() is required to succeed.
        else:
            django.setup()
    ...

django.setup() 启动程序

  • 这个代码在 django/init.py 中
def setup(set_prefix=True):
    """
    Configure the settings (this happens as a side effect of accessing the
    first setting), configure logging and populate the app registry.
    Set the thread-local urlresolvers script prefix if `set_prefix` is True.
    """
    ...
    configure_logging(settings.LOGGING_CONFIG, settings.LOGGING)
    if set_prefix:
        set_script_prefix(
            '/' if settings.FORCE_SCRIPT_NAME is None else settings.FORCE_SCRIPT_NAME
        )
    apps.populate(settings.INSTALLED_APPS)
  • configure_logging 配置日志信息,set_script_prefix 设置一些前缀补充完整,这两个方法直接过。我们看如下有价值的代码,是调用了模块from django.apps import apps的类方法populate,加载 settings.INSTALLED_APPS 中的自定义app(字符串),以及 对应的 models 模块,并保存在 django.apps 中,这是一个全局的 Apps 类(这个类在 django.apps.registry 中定义,populate(self, installed_apps=None) 是它的主要方法。)实例。是一个已经安装应用的注册表,这个注册表存储着配置信息以及用来自省,同时也维护这模型的列表。

模型的加载

    def populate(self, installed_apps=None):
        # populate() might be called by two threads in parallel on servers
        # that create threads before initializing the WSGI callable.
        with self._lock:
            ...
            for entry in installed_apps:
                if isinstance(entry, AppConfig):
                    app_config = entry
                else:
                    app_config = AppConfig.create(entry)
                ...
                self.app_configs[app_config.label] = app_config
                app_config.apps = self
            ...
  • populate函数通过with开启了self._lock = threading.Lock()锁,所以是线程安全的,然后循环installed_apps,如果是AppConfig实例类型就返回,否则就去加载 app 并实例化该 app 的类对象app_config = AppConfig.create(entry),保存在 self.app_configs 中。
  • create方法是 classmethod 的,这是一个工厂模式,它根据参数来构造出 AppConfig(app_name, app_module) 这样的实例。
        try:
            app_name = cls.name
        except AttributeError:
            raise ImproperlyConfigured(
                "'%s' must supply a name attribute." % entry)

        # Ensure app_name points to a valid module.
        try:
            app_module = import_module(app_name)
  • 其中 app_name 表示 INSTALLED_APPS 中指定的应用字符串,app_module 表示根据 app_name 加载到的module。在 AppConfig 实例的初始化方法中,会记录这些应用的标签、文件路径等信息,最终将这些实例会保存在其属性中。
            # Phase 2: import models modules.
            for app_config in self.app_configs.values():
            # 当加载完毕后,进行导入各个app模块
                app_config.import_models()

            self.clear_cache()

            self.models_ready = True

            # Phase 3: run ready() methods of app configs.
            for app_config in self.get_app_configs():
            # 然后修改其状态
                app_config.ready()

            self.ready = True
            self.ready_event.set()
            
#输出 self.get_app_configs()
odict_values([<AdminConfig: admin>, 
<AuthConfig: auth>, 
<ContentTypesConfig: contenttypes>, 
<SessionsConfig: sessions>, 
<MessagesConfig: messages>,
...
<AppConfig: pure_pagination>])

#输出 import_models 函数中的 self.models_module
<module 'django.contrib.admin.models' from 'C:\\mooc_project\\lib\\site-packages\\django\\contrib\\admin\\models.py'>
<module 'django.contrib.auth.models' from 'C:\\mooc_project\\lib\\site-packages\\django\\contrib\\auth\\models.py'>
<module 'django.contrib.contenttypes.models' from 'C:\\mooc_project\\lib\\site-packages\\django\\contrib\\contenttypes\\models.py'>
<module 'django.contrib.sessions.models' from 'C:\\mooc_project\\lib\\site-packages\\django\\contrib\\sessions\\models.py'>
#呈现结果的对象来看,self.models 已经装载了这些 已经加载好 的模型对象。
django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS, but settings are not configured是一个常见的错误。这个错误提示表明在访问设置之前,需要配置Django的设置。 解决这个问题的方法有两种: 1. 定义环境变量DJANGO_SETTINGS_MODULE: 在项目的根目录中,可以通过在终端中使用export命令来定义环境变量DJANGO_SETTINGS_MODULE,例如: export DJANGO_SETTINGS_MODULE=<项目名称>.settings 然后再次运行项目,应该就不会再报错了。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [django调试问题django.core.exceptions.ImproperlyConfigured](https://blog.csdn.net/weixin_44602651/article/details/120456631)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [Django报错:django.core.exceptions.ImproperlyConfigured: Requested setting INSTALLED_APPS解决办法](https://blog.csdn.net/jyr2014/article/details/126753776)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值