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 the
initfunction of the
ManagementUtility`.
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.py
Let'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 of
populate`, 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