config.py 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. from importlib import import_module
  2. import os
  3. from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured
  4. from django.utils.module_loading import module_has_submodule
  5. from django.utils._os import upath
  6. MODELS_MODULE_NAME = 'models'
  7. class AppConfig(object):
  8. """
  9. Class representing a Django application and its configuration.
  10. """
  11. def __init__(self, app_name, app_module):
  12. # Full Python path to the application eg. 'django.contrib.admin'.
  13. self.name = app_name
  14. # Root module for the application eg. <module 'django.contrib.admin'
  15. # from 'django/contrib/admin/__init__.pyc'>.
  16. self.module = app_module
  17. # The following attributes could be defined at the class level in a
  18. # subclass, hence the test-and-set pattern.
  19. # Last component of the Python path to the application eg. 'admin'.
  20. # This value must be unique across a Django project.
  21. if not hasattr(self, 'label'):
  22. self.label = app_name.rpartition(".")[2]
  23. # Human-readable name for the application eg. "Admin".
  24. if not hasattr(self, 'verbose_name'):
  25. self.verbose_name = self.label.title()
  26. # Filesystem path to the application directory eg.
  27. # u'/usr/lib/python2.7/dist-packages/django/contrib/admin'. Unicode on
  28. # Python 2 and a str on Python 3.
  29. if not hasattr(self, 'path'):
  30. self.path = self._path_from_module(app_module)
  31. # Module containing models eg. <module 'django.contrib.admin.models'
  32. # from 'django/contrib/admin/models.pyc'>. Set by import_models().
  33. # None if the application doesn't have a models module.
  34. self.models_module = None
  35. # Mapping of lower case model names to model classes. Initially set to
  36. # None to prevent accidental access before import_models() runs.
  37. self.models = None
  38. def __repr__(self):
  39. return '<%s: %s>' % (self.__class__.__name__, self.label)
  40. def _path_from_module(self, module):
  41. """Attempt to determine app's filesystem path from its module."""
  42. # See #21874 for extended discussion of the behavior of this method in
  43. # various cases.
  44. # Convert paths to list because Python 3.3 _NamespacePath does not
  45. # support indexing.
  46. paths = list(getattr(module, '__path__', []))
  47. if len(paths) != 1:
  48. filename = getattr(module, '__file__', None)
  49. if filename is not None:
  50. paths = [os.path.dirname(filename)]
  51. if len(paths) > 1:
  52. raise ImproperlyConfigured(
  53. "The app module %r has multiple filesystem locations (%r); "
  54. "you must configure this app with an AppConfig subclass "
  55. "with a 'path' class attribute." % (module, paths))
  56. elif not paths:
  57. raise ImproperlyConfigured(
  58. "The app module %r has no filesystem location, "
  59. "you must configure this app with an AppConfig subclass "
  60. "with a 'path' class attribute." % (module,))
  61. return upath(paths[0])
  62. @classmethod
  63. def create(cls, entry):
  64. """
  65. Factory that creates an app config from an entry in INSTALLED_APPS.
  66. """
  67. try:
  68. # If import_module succeeds, entry is a path to an app module,
  69. # which may specify an app config class with default_app_config.
  70. # Otherwise, entry is a path to an app config class or an error.
  71. module = import_module(entry)
  72. except ImportError:
  73. mod_path, _, cls_name = entry.rpartition('.')
  74. # Raise the original exception when entry cannot be a path to an
  75. # app config class.
  76. if not mod_path:
  77. raise
  78. else:
  79. try:
  80. # If this works, the app module specifies an app config class.
  81. entry = module.default_app_config
  82. except AttributeError:
  83. # Otherwise, it simply uses the default app config class.
  84. return cls(entry, module)
  85. else:
  86. mod_path, _, cls_name = entry.rpartition('.')
  87. # If we're reaching this point, we must load the app config class
  88. # located at <mod_path>.<cls_name>.
  89. # Avoid django.utils.module_loading.import_by_path because it
  90. # masks errors -- it reraises ImportError as ImproperlyConfigured.
  91. mod = import_module(mod_path)
  92. try:
  93. cls = getattr(mod, cls_name)
  94. except AttributeError:
  95. # Emulate the error that "from <mod_path> import <cls_name>"
  96. # would raise when <mod_path> exists but not <cls_name>, with
  97. # more context (Python just says "cannot import name ...").
  98. raise ImportError(
  99. "cannot import name '%s' from '%s'" % (cls_name, mod_path))
  100. # Check for obvious errors. (This check prevents duck typing, but
  101. # it could be removed if it became a problem in practice.)
  102. if not issubclass(cls, AppConfig):
  103. raise ImproperlyConfigured(
  104. "'%s' isn't a subclass of AppConfig." % entry)
  105. # Obtain app name here rather than in AppClass.__init__ to keep
  106. # all error checking for entries in INSTALLED_APPS in one place.
  107. try:
  108. app_name = cls.name
  109. except AttributeError:
  110. raise ImproperlyConfigured(
  111. "'%s' must supply a name attribute." % entry)
  112. # Ensure app_name points to a valid module.
  113. app_module = import_module(app_name)
  114. # Entry is a path to an app config class.
  115. return cls(app_name, app_module)
  116. def check_models_ready(self):
  117. """
  118. Raises an exception if models haven't been imported yet.
  119. """
  120. if self.models is None:
  121. raise AppRegistryNotReady(
  122. "Models for app '%s' haven't been imported yet." % self.label)
  123. def get_model(self, model_name):
  124. """
  125. Returns the model with the given case-insensitive model_name.
  126. Raises LookupError if no model exists with this name.
  127. """
  128. self.check_models_ready()
  129. try:
  130. return self.models[model_name.lower()]
  131. except KeyError:
  132. raise LookupError(
  133. "App '%s' doesn't have a '%s' model." % (self.label, model_name))
  134. def get_models(self, include_auto_created=False,
  135. include_deferred=False, include_swapped=False):
  136. """
  137. Returns an iterable of models.
  138. By default, the following models aren't included:
  139. - auto-created models for many-to-many relations without
  140. an explicit intermediate table,
  141. - models created to satisfy deferred attribute queries,
  142. - models that have been swapped out.
  143. Set the corresponding keyword argument to True to include such models.
  144. Keyword arguments aren't documented; they're a private API.
  145. """
  146. self.check_models_ready()
  147. for model in self.models.values():
  148. if model._deferred and not include_deferred:
  149. continue
  150. if model._meta.auto_created and not include_auto_created:
  151. continue
  152. if model._meta.swapped and not include_swapped:
  153. continue
  154. yield model
  155. def import_models(self, all_models):
  156. # Dictionary of models for this app, primarily maintained in the
  157. # 'all_models' attribute of the Apps this AppConfig is attached to.
  158. # Injected as a parameter because it gets populated when models are
  159. # imported, which might happen before populate() imports models.
  160. self.models = all_models
  161. if module_has_submodule(self.module, MODELS_MODULE_NAME):
  162. models_module_name = '%s.%s' % (self.name, MODELS_MODULE_NAME)
  163. self.models_module = import_module(models_module_name)
  164. def ready(self):
  165. """
  166. Override this method in subclasses to run code when Django starts.
  167. """