Je vais vous expliquer le processus menant à la rédaction de cet article, j'avais cette question sur teratail Je ne sais pas comment enseigner le projet lors de l'activation du modèle Django
Le contenu de la question était le suivant.
Pourquoi le module INSTALLED_APPS de Django serait-il placé comme ʻapp name.apps.app name config
, En termes de structure de répertoires, il devrait s'agir de
../app name / apps.app name config`.
Je voudrais donc expliquer le code source de Django pour ʻINSTALLED_APPS`. Si vous êtes intéressé par le cœur de Django, veuillez rester avec nous jusqu'à la fin. : détendu:
Pour expliquer, je vais créer un projet simple appelé django_test
, la structure des répertoires est la suivante.
djnago_test
|-- django_test
|-- |-- __init__.py
|-- |-- asgi.py
|-- |-- settings.py
|-- |-- urls.py
|-- |-- wsgi.py
|-- manage.py
runserver Lancez votre projet Django depuis la ligne de commande.
python manage.py runserver
Alors que s'est-il passé après cela, jetons un coup d'œil au contenu de 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
ajoute les données du dictionnaire de clé et de valeur à ʻenviron`, si la clé existe, obtient la valeur.
management
.
--Exécute ʻexecute_from_command_line (sys.argv) `.Tout d'abord, regardons le contenu de sys.argv
, le chemin de manage.py et la commande d'exécution.
['manage.py', 'runserver']
Ensuite, regardez le contenu de ʻexecute_from_command_line (sys.argv) `.
management/__init__.py
def execute_from_command_line(argv=None):
"""Run a ManagementUtility."""
utility = ManagementUtility(argv)
utility.execute()
Le contenu est très simple, il prend la valeur de sys.argv
,
J'ai instancié l'utilitaire de gestion et j'ai exécuté la fonction «exécuter».
Jetons un coup d'œil à la fonction __init__
de 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
dans ce cas:
self.arg
== sys.argv
== ['manage.py', 'runserver']
--self.prog_name
== chemin de manage.py
Regardons le suivant. Que fait la fonction ʻexecute` Le contenu de la fonction est très long, donc je n'expliquerai que les parties importantes.
management.py
try:
subcommand = self.argv[1]
except IndexError:
subcommand = 'help'
python manage.py runserver
Lors de l'exécution, la valeur de la sous-commande sera runserver
.
Entrez ensuite le bloc ci-dessous.
management.py
...
if subcommand == 'runserver' and '--noreload' not in self.argv:
try:
autoreload.check_errors(django.setup)()
...
Jetons un œil au contenu de 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)
À ce stade, le processus lié à ʻINSTALLED_APPSest devenu clair, Jetons un coup d'œil à la source de
populate`, c'est assez long, donc je n'expliquerai que les parties importantes.
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
...
Le contenu de cette ʻinstalled_apps` est le suivant, boucle et sort un par un et lance le processus suivant. Une chose à noter est que le contenu comme `` 'django.contrib.admin' 'est de type ** string **.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
Le contenu de la boucle est un jugement conditionnel de la relation d'héritage pour les éléments contenus dans ʻINSTALLED_APPS`.
if isinstance(entry, AppConfig):
app_config = entry
else:
app_config = AppConfig.create(entry)
Bien sûr, ce n'est plus qu'une chaîne maintenant, donc il va dans le bloc else.
app_config = AppConfig.create(entry)
Jetons un œil au contenu de 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
...
À ce stade, je voudrais utiliser la fonction ʻimport_module, Créez une application ʻusers ʻapp et ajoutez-la à ʻINSTALLED_APPS
.
python manage.py startapp users
INSTALLED_APPS= [
...
users or users.apps.UsersConfig
]
Lorsqu'il est ajouté en tant que «utilisateurs».
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'>
Il a trouvé l'application correctement.
Lorsqu'il est ajouté en tant que 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
Je n'arrive pas à trouver l'application, je suis donc dans le bloc ci-dessous.
config.py
except ImportError:
module = None
mod_path, _, cls_name = entry.rpartition('.')
if not mod_path:
raise
mod_path, _, cls_name = entry.rpartition ('.')
Est exécuté et
La valeur de mod_path
sera ʻusers.apps et
cls_name sera ʻUsersConfig
.
Je vais le tester à nouveau.
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'>
Il a trouvé l'application.
Recommended Posts