config.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  1. import inspect
  2. import os
  3. import warnings
  4. from importlib import import_module
  5. from django.core.exceptions import ImproperlyConfigured
  6. from django.utils.deprecation import RemovedInDjango41Warning
  7. from django.utils.functional import cached_property
  8. from django.utils.module_loading import import_string, module_has_submodule
  9. APPS_MODULE_NAME = 'apps'
  10. MODELS_MODULE_NAME = 'models'
  11. class AppConfig:
  12. """Class representing a Django application and its configuration."""
  13. def __init__(self, app_name, app_module):
  14. # Full Python path to the application e.g. 'django.contrib.admin'.
  15. self.name = app_name
  16. # Root module for the application e.g. <module 'django.contrib.admin'
  17. # from 'django/contrib/admin/__init__.py'>.
  18. self.module = app_module
  19. # Reference to the Apps registry that holds this AppConfig. Set by the
  20. # registry when it registers the AppConfig instance.
  21. self.apps = None
  22. # The following attributes could be defined at the class level in a
  23. # subclass, hence the test-and-set pattern.
  24. # Last component of the Python path to the application e.g. 'admin'.
  25. # This value must be unique across a Django project.
  26. if not hasattr(self, 'label'):
  27. self.label = app_name.rpartition(".")[2]
  28. if not self.label.isidentifier():
  29. raise ImproperlyConfigured(
  30. "The app label '%s' is not a valid Python identifier." % self.label
  31. )
  32. # Human-readable name for the application e.g. "Admin".
  33. if not hasattr(self, 'verbose_name'):
  34. self.verbose_name = self.label.title()
  35. # Filesystem path to the application directory e.g.
  36. # '/path/to/django/contrib/admin'.
  37. if not hasattr(self, 'path'):
  38. self.path = self._path_from_module(app_module)
  39. # Module containing models e.g. <module 'django.contrib.admin.models'
  40. # from 'django/contrib/admin/models.py'>. Set by import_models().
  41. # None if the application doesn't have a models module.
  42. self.models_module = None
  43. # Mapping of lowercase model names to model classes. Initially set to
  44. # None to prevent accidental access before import_models() runs.
  45. self.models = None
  46. def __repr__(self):
  47. return '<%s: %s>' % (self.__class__.__name__, self.label)
  48. @cached_property
  49. def default_auto_field(self):
  50. from django.conf import settings
  51. return settings.DEFAULT_AUTO_FIELD
  52. @property
  53. def _is_default_auto_field_overridden(self):
  54. return self.__class__.default_auto_field is not AppConfig.default_auto_field
  55. def _path_from_module(self, module):
  56. """Attempt to determine app's filesystem path from its module."""
  57. # See #21874 for extended discussion of the behavior of this method in
  58. # various cases.
  59. # Convert paths to list because Python's _NamespacePath doesn't support
  60. # indexing.
  61. paths = list(getattr(module, '__path__', []))
  62. if len(paths) != 1:
  63. filename = getattr(module, '__file__', None)
  64. if filename is not None:
  65. paths = [os.path.dirname(filename)]
  66. else:
  67. # For unknown reasons, sometimes the list returned by __path__
  68. # contains duplicates that must be removed (#25246).
  69. paths = list(set(paths))
  70. if len(paths) > 1:
  71. raise ImproperlyConfigured(
  72. "The app module %r has multiple filesystem locations (%r); "
  73. "you must configure this app with an AppConfig subclass "
  74. "with a 'path' class attribute." % (module, paths))
  75. elif not paths:
  76. raise ImproperlyConfigured(
  77. "The app module %r has no filesystem location, "
  78. "you must configure this app with an AppConfig subclass "
  79. "with a 'path' class attribute." % module)
  80. return paths[0]
  81. @classmethod
  82. def create(cls, entry):
  83. """
  84. Factory that creates an app config from an entry in INSTALLED_APPS.
  85. """
  86. # create() eventually returns app_config_class(app_name, app_module).
  87. app_config_class = None
  88. app_config_name = None
  89. app_name = None
  90. app_module = None
  91. # If import_module succeeds, entry points to the app module.
  92. try:
  93. app_module = import_module(entry)
  94. except Exception:
  95. pass
  96. else:
  97. # If app_module has an apps submodule that defines a single
  98. # AppConfig subclass, use it automatically.
  99. # To prevent this, an AppConfig subclass can declare a class
  100. # variable default = False.
  101. # If the apps module defines more than one AppConfig subclass,
  102. # the default one can declare default = True.
  103. if module_has_submodule(app_module, APPS_MODULE_NAME):
  104. mod_path = '%s.%s' % (entry, APPS_MODULE_NAME)
  105. mod = import_module(mod_path)
  106. # Check if there's exactly one AppConfig candidate,
  107. # excluding those that explicitly define default = False.
  108. app_configs = [
  109. (name, candidate)
  110. for name, candidate in inspect.getmembers(mod, inspect.isclass)
  111. if (
  112. issubclass(candidate, cls) and
  113. candidate is not cls and
  114. getattr(candidate, 'default', True)
  115. )
  116. ]
  117. if len(app_configs) == 1:
  118. app_config_class = app_configs[0][1]
  119. app_config_name = '%s.%s' % (mod_path, app_configs[0][0])
  120. else:
  121. # Check if there's exactly one AppConfig subclass,
  122. # among those that explicitly define default = True.
  123. app_configs = [
  124. (name, candidate)
  125. for name, candidate in app_configs
  126. if getattr(candidate, 'default', False)
  127. ]
  128. if len(app_configs) > 1:
  129. candidates = [repr(name) for name, _ in app_configs]
  130. raise RuntimeError(
  131. '%r declares more than one default AppConfig: '
  132. '%s.' % (mod_path, ', '.join(candidates))
  133. )
  134. elif len(app_configs) == 1:
  135. app_config_class = app_configs[0][1]
  136. app_config_name = '%s.%s' % (mod_path, app_configs[0][0])
  137. # If app_module specifies a default_app_config, follow the link.
  138. # default_app_config is deprecated, but still takes over the
  139. # automatic detection for backwards compatibility during the
  140. # deprecation period.
  141. try:
  142. new_entry = app_module.default_app_config
  143. except AttributeError:
  144. # Use the default app config class if we didn't find anything.
  145. if app_config_class is None:
  146. app_config_class = cls
  147. app_name = entry
  148. else:
  149. message = (
  150. '%r defines default_app_config = %r. ' % (entry, new_entry)
  151. )
  152. if new_entry == app_config_name:
  153. message += (
  154. 'Django now detects this configuration automatically. '
  155. 'You can remove default_app_config.'
  156. )
  157. else:
  158. message += (
  159. "However, Django's automatic detection %s. You should "
  160. "move the default config class to the apps submodule "
  161. "of your application and, if this module defines "
  162. "several config classes, mark the default one with "
  163. "default = True." % (
  164. "picked another configuration, %r" % app_config_name
  165. if app_config_name
  166. else "did not find this configuration"
  167. )
  168. )
  169. warnings.warn(message, RemovedInDjango41Warning, stacklevel=2)
  170. entry = new_entry
  171. app_config_class = None
  172. # If import_string succeeds, entry is an app config class.
  173. if app_config_class is None:
  174. try:
  175. app_config_class = import_string(entry)
  176. except Exception:
  177. pass
  178. # If both import_module and import_string failed, it means that entry
  179. # doesn't have a valid value.
  180. if app_module is None and app_config_class is None:
  181. # If the last component of entry starts with an uppercase letter,
  182. # then it was likely intended to be an app config class; if not,
  183. # an app module. Provide a nice error message in both cases.
  184. mod_path, _, cls_name = entry.rpartition('.')
  185. if mod_path and cls_name[0].isupper():
  186. # We could simply re-trigger the string import exception, but
  187. # we're going the extra mile and providing a better error
  188. # message for typos in INSTALLED_APPS.
  189. # This may raise ImportError, which is the best exception
  190. # possible if the module at mod_path cannot be imported.
  191. mod = import_module(mod_path)
  192. candidates = [
  193. repr(name)
  194. for name, candidate in inspect.getmembers(mod, inspect.isclass)
  195. if issubclass(candidate, cls) and candidate is not cls
  196. ]
  197. msg = "Module '%s' does not contain a '%s' class." % (mod_path, cls_name)
  198. if candidates:
  199. msg += ' Choices are: %s.' % ', '.join(candidates)
  200. raise ImportError(msg)
  201. else:
  202. # Re-trigger the module import exception.
  203. import_module(entry)
  204. # Check for obvious errors. (This check prevents duck typing, but
  205. # it could be removed if it became a problem in practice.)
  206. if not issubclass(app_config_class, AppConfig):
  207. raise ImproperlyConfigured(
  208. "'%s' isn't a subclass of AppConfig." % entry)
  209. # Obtain app name here rather than in AppClass.__init__ to keep
  210. # all error checking for entries in INSTALLED_APPS in one place.
  211. if app_name is None:
  212. try:
  213. app_name = app_config_class.name
  214. except AttributeError:
  215. raise ImproperlyConfigured(
  216. "'%s' must supply a name attribute." % entry
  217. )
  218. # Ensure app_name points to a valid module.
  219. try:
  220. app_module = import_module(app_name)
  221. except ImportError:
  222. raise ImproperlyConfigured(
  223. "Cannot import '%s'. Check that '%s.%s.name' is correct." % (
  224. app_name,
  225. app_config_class.__module__,
  226. app_config_class.__qualname__,
  227. )
  228. )
  229. # Entry is a path to an app config class.
  230. return app_config_class(app_name, app_module)
  231. def get_model(self, model_name, require_ready=True):
  232. """
  233. Return the model with the given case-insensitive model_name.
  234. Raise LookupError if no model exists with this name.
  235. """
  236. if require_ready:
  237. self.apps.check_models_ready()
  238. else:
  239. self.apps.check_apps_ready()
  240. try:
  241. return self.models[model_name.lower()]
  242. except KeyError:
  243. raise LookupError(
  244. "App '%s' doesn't have a '%s' model." % (self.label, model_name))
  245. def get_models(self, include_auto_created=False, include_swapped=False):
  246. """
  247. Return an iterable of models.
  248. By default, the following models aren't included:
  249. - auto-created models for many-to-many relations without
  250. an explicit intermediate table,
  251. - models that have been swapped out.
  252. Set the corresponding keyword argument to True to include such models.
  253. Keyword arguments aren't documented; they're a private API.
  254. """
  255. self.apps.check_models_ready()
  256. for model in self.models.values():
  257. if model._meta.auto_created and not include_auto_created:
  258. continue
  259. if model._meta.swapped and not include_swapped:
  260. continue
  261. yield model
  262. def import_models(self):
  263. # Dictionary of models for this app, primarily maintained in the
  264. # 'all_models' attribute of the Apps this AppConfig is attached to.
  265. self.models = self.apps.all_models[self.label]
  266. if module_has_submodule(self.module, MODELS_MODULE_NAME):
  267. models_module_name = '%s.%s' % (self.name, MODELS_MODULE_NAME)
  268. self.models_module = import_module(models_module_name)
  269. def ready(self):
  270. """
  271. Override this method in subclasses to run code when Django starts.
  272. """