You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

208 lines
8.1 KiB

  1. import os
  2. from importlib import import_module
  3. from django.core.exceptions import AppRegistryNotReady, ImproperlyConfigured
  4. from django.utils._os import upath
  5. from django.utils.module_loading import module_has_submodule
  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's _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. else:
  52. # For unknown reasons, sometimes the list returned by __path__
  53. # contains duplicates that must be removed (#25246).
  54. paths = list(set(paths))
  55. if len(paths) > 1:
  56. raise ImproperlyConfigured(
  57. "The app module %r has multiple filesystem locations (%r); "
  58. "you must configure this app with an AppConfig subclass "
  59. "with a 'path' class attribute." % (module, paths))
  60. elif not paths:
  61. raise ImproperlyConfigured(
  62. "The app module %r has no filesystem location, "
  63. "you must configure this app with an AppConfig subclass "
  64. "with a 'path' class attribute." % (module,))
  65. return upath(paths[0])
  66. @classmethod
  67. def create(cls, entry):
  68. """
  69. Factory that creates an app config from an entry in INSTALLED_APPS.
  70. """
  71. try:
  72. # If import_module succeeds, entry is a path to an app module,
  73. # which may specify an app config class with default_app_config.
  74. # Otherwise, entry is a path to an app config class or an error.
  75. module = import_module(entry)
  76. except ImportError:
  77. # Track that importing as an app module failed. If importing as an
  78. # app config class fails too, we'll trigger the ImportError again.
  79. module = None
  80. mod_path, _, cls_name = entry.rpartition('.')
  81. # Raise the original exception when entry cannot be a path to an
  82. # app config class.
  83. if not mod_path:
  84. raise
  85. else:
  86. try:
  87. # If this works, the app module specifies an app config class.
  88. entry = module.default_app_config
  89. except AttributeError:
  90. # Otherwise, it simply uses the default app config class.
  91. return cls(entry, module)
  92. else:
  93. mod_path, _, cls_name = entry.rpartition('.')
  94. # If we're reaching this point, we must attempt to load the app config
  95. # class located at <mod_path>.<cls_name>
  96. mod = import_module(mod_path)
  97. try:
  98. cls = getattr(mod, cls_name)
  99. except AttributeError:
  100. if module is None:
  101. # If importing as an app module failed, that error probably
  102. # contains the most informative traceback. Trigger it again.
  103. import_module(entry)
  104. else:
  105. raise
  106. # Check for obvious errors. (This check prevents duck typing, but
  107. # it could be removed if it became a problem in practice.)
  108. if not issubclass(cls, AppConfig):
  109. raise ImproperlyConfigured(
  110. "'%s' isn't a subclass of AppConfig." % entry)
  111. # Obtain app name here rather than in AppClass.__init__ to keep
  112. # all error checking for entries in INSTALLED_APPS in one place.
  113. try:
  114. app_name = cls.name
  115. except AttributeError:
  116. raise ImproperlyConfigured(
  117. "'%s' must supply a name attribute." % entry)
  118. # Ensure app_name points to a valid module.
  119. app_module = import_module(app_name)
  120. # Entry is a path to an app config class.
  121. return cls(app_name, app_module)
  122. def check_models_ready(self):
  123. """
  124. Raises an exception if models haven't been imported yet.
  125. """
  126. if self.models is None:
  127. raise AppRegistryNotReady(
  128. "Models for app '%s' haven't been imported yet." % self.label)
  129. def get_model(self, model_name):
  130. """
  131. Returns the model with the given case-insensitive model_name.
  132. Raises LookupError if no model exists with this name.
  133. """
  134. self.check_models_ready()
  135. try:
  136. return self.models[model_name.lower()]
  137. except KeyError:
  138. raise LookupError(
  139. "App '%s' doesn't have a '%s' model." % (self.label, model_name))
  140. def get_models(self, include_auto_created=False,
  141. include_deferred=False, include_swapped=False):
  142. """
  143. Returns an iterable of models.
  144. By default, the following models aren't included:
  145. - auto-created models for many-to-many relations without
  146. an explicit intermediate table,
  147. - models created to satisfy deferred attribute queries,
  148. - models that have been swapped out.
  149. Set the corresponding keyword argument to True to include such models.
  150. Keyword arguments aren't documented; they're a private API.
  151. """
  152. self.check_models_ready()
  153. for model in self.models.values():
  154. if model._deferred and not include_deferred:
  155. continue
  156. if model._meta.auto_created and not include_auto_created:
  157. continue
  158. if model._meta.swapped and not include_swapped:
  159. continue
  160. yield model
  161. def import_models(self, all_models):
  162. # Dictionary of models for this app, primarily maintained in the
  163. # 'all_models' attribute of the Apps this AppConfig is attached to.
  164. # Injected as a parameter because it gets populated when models are
  165. # imported, which might happen before populate() imports models.
  166. self.models = all_models
  167. if module_has_submodule(self.module, MODELS_MODULE_NAME):
  168. models_module_name = '%s.%s' % (self.name, MODELS_MODULE_NAME)
  169. self.models_module = import_module(models_module_name)
  170. def ready(self):
  171. """
  172. Override this method in subclasses to run code when Django starts.
  173. """