
I will explain the process leading up to this article, I had this question on teratail, I don't know how to teach the project when enabling the Django model
The content of the question was as follows.
Why would Django's INSTALLED_APPS module be put in like ʻapp name.apps.app name config
, In terms of directory structure, it should be../app name / apps.app name config`.
So I'd like to explain Django's source code for ʻINSTALLED_APPS`. If you're interested in Django's core, stay tuned to the end. : relaxed:
To explain, I will create a simple project called django_test, the directory structure is as follows.
djnago_test
|-- django_test
|-- |-- __init__.py
|-- |-- asgi.py
|-- |-- settings.py
|-- |-- urls.py
|-- |-- wsgi.py
|-- manage.py
runserver Launch your Django project from the command line.
python manage.py runserver
So what happened after that, let's take a look at the contents of manage.py.
manage.py
#!/usr/bin/env python
"""Django's command-line utility for administrative tasks."""
import os
import sys
def main():
    os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')
    try:
        from django.core.management import execute_from_command_line
    except ImportError as exc:
        raise ImportError(
            "Couldn't import Django. Are you sure it's installed and "
            "available on your PYTHONPATH environment variable? Did you "
            "forget to activate a virtual environment?"
        ) from exc
    execute_from_command_line(sys.argv)
if __name__ == '__main__':
    main()
--setdefault adds the dictionary data of key and value to ʻenviron, if the key exists, it gets the value.  --Import the managementmodule.  --Execute ʻexecute_from_command_line (sys.argv).
First, let's look at the contents of sys.argv, the path of manage.py and the execution command.
['manage.py', 'runserver']
Next, look at the contents of ʻexecute_from_command_line (sys.argv)`.
management/__init__.py
def execute_from_command_line(argv=None):
    """Run a ManagementUtility."""
    utility = ManagementUtility(argv)
    utility.execute()
The content is very simple, it takes the value of sys.argv,
I instantiated the ManagementUtility and executed the ʻexecutefunction.  Let's take a look at theinitfunction of theManagementUtility`.
management.py
    def __init__(self, argv=None):
        self.argv = argv or sys.argv[:]
        self.prog_name = os.path.basename(self.argv[0])
        if self.prog_name == '__main__.py':
            self.prog_name = 'python -m django'
        self.settings_exception = None
in this case:
self.arg == sys.argv == ['manage.py', 'runserver']
--self.prog_name == path of manage.pyLet's look at the next. What did the ʻexecute` function do? The content of the function is very long, so I will explain only the important parts.
management.py
try:
    subcommand = self.argv[1]
except IndexError:
    subcommand = 'help'
python manage.py runserver When running, the value of subcommand will be runserver.
Then enter the block below.
management.py
...
if subcommand == 'runserver' and '--noreload' not in self.argv:
   try:
      autoreload.check_errors(django.setup)()
...
Let's take a look at the contents of 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.
    """
    from django.apps import apps
    from django.conf import settings
    from django.urls import set_script_prefix
    from django.utils.log import configure_logging
    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)
At this point, the process related to ʻINSTALLED_APPShas become clear,  Let's take a look at the source ofpopulate`, it's fairly long, so I'll explain only the important parts.
registry.py
...
    def populate(self, installed_apps=None):
        ...
            for entry in installed_apps:
                if isinstance(entry, AppConfig):
                    app_config = entry
                else:
                    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
                app_config.apps = self
...
The contents of this ʻinstalled_appsare as follows, loop and take out one by one and start the next process.  One thing to note is that content like'django.contrib.admin'` is of type ** string **.
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
]
The content of the loop is a conditional judgment of the inheritance relationship for the elements contained in ʻINSTALLED_APPS`.
if isinstance(entry, AppConfig):
    app_config = entry
else:
    app_config = AppConfig.create(entry)
Of course, it's just a string right now, so it goes into the else block.
app_config = AppConfig.create(entry)
Let's take a look at the contents of create ().
config.py
    def create(cls, entry):
        ...
        try:
            module = import_module(entry)
        except ImportError:
            module = None
            mod_path, _, cls_name = entry.rpartition('.')
            if not mod_path:
                raise
        ...
At this point, I'd like to actually use the ʻimport_module function,  Create a ʻusers ʻapp and add it to ʻINSTALLED_APPS.
python manage.py startapp users
INSTALLED_APPS= [
...
users or users.apps.UsersConfig
]
When added as ʻusers`.
test.py
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')
from importlib import import_module
print(import_module("users"))
# <module 'users' from '/Users/user/django/django_test/users/__init__.py'>
He found the app properly.
ʻWhen added as users.apps.UsersConfig`.
test.py
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')
from importlib import import_module
print(import_module("users.apps.UsersConfig"))
# ModuleNotFoundError: No module named 'users.apps.UsersConfig'; 'users.apps' is not a package
I can't seem to find the app, so I'm in the block below.
config.py
except ImportError:
    module = None
    mod_path, _, cls_name = entry.rpartition('.')
    if not mod_path:
       raise
mod_path, _, cls_name = entry.rpartition ('.') Is executed and
The value of mod_path will be ʻusers.apps and cls_name will be ʻUsersConfig.
I will test it again.
main.py
import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_test.settings')
from importlib import import_module
mod_path, _, cls_name = "users.apps.UsersConfig".rpartition('.')
print(import_module(mod_path))
# <module 'users.apps' from '/Users/user/django/django_test/users/apps.py'>
He found the app.
Recommended Posts