mirror of
				https://github.com/django/django.git
				synced 2025-10-31 01:25:32 +00:00 
			
		
		
		
	Fixed #14007 -- Added model discovery in models module without the need to specify app_label.
Thanks mark@ and Aramgutang for work on the patch.
This commit is contained in:
		| @@ -19,7 +19,7 @@ from django.db.models.query_utils import DeferredAttribute, deferred_class_facto | ||||
| from django.db.models.deletion import Collector | ||||
| from django.db.models.options import Options | ||||
| from django.db.models import signals | ||||
| from django.db.models.loading import register_models, get_model | ||||
| from django.db.models.loading import register_models, get_model, MODELS_MODULE_NAME | ||||
| from django.utils.translation import ugettext_lazy as _ | ||||
| from django.utils.functional import curry | ||||
| from django.utils.encoding import force_str, force_text | ||||
| @@ -86,10 +86,22 @@ class ModelBase(type): | ||||
|         base_meta = getattr(new_class, '_meta', None) | ||||
|  | ||||
|         if getattr(meta, 'app_label', None) is None: | ||||
|             # Figure out the app_label by looking one level up. | ||||
|             # Figure out the app_label by looking one level up from the package | ||||
|             # or module named 'models'. If no such package or module exists, | ||||
|             # fall back to looking one level up from the module this model is | ||||
|             # defined in. | ||||
|  | ||||
|             # For 'django.contrib.sites.models', this would be 'sites'. | ||||
|             # For 'geo.models.places' this would be 'geo'. | ||||
|  | ||||
|             model_module = sys.modules[new_class.__module__] | ||||
|             kwargs = {"app_label": model_module.__name__.split('.')[-2]} | ||||
|             package_components = model_module.__name__.split('.') | ||||
|             package_components.reverse()  # find the last occurrence of 'models' | ||||
|             try: | ||||
|                 app_label_index = package_components.index(MODELS_MODULE_NAME) + 1 | ||||
|             except ValueError: | ||||
|                 app_label_index = 1 | ||||
|             kwargs = {"app_label": package_components[app_label_index]} | ||||
|         else: | ||||
|             kwargs = {} | ||||
|  | ||||
|   | ||||
| @@ -15,6 +15,8 @@ import os | ||||
| __all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models', | ||||
|         'load_app', 'app_cache_ready') | ||||
|  | ||||
| MODELS_MODULE_NAME = 'models' | ||||
|  | ||||
|  | ||||
| class UnavailableApp(Exception): | ||||
|     pass | ||||
| @@ -98,12 +100,12 @@ class AppCache(object): | ||||
|         self.nesting_level += 1 | ||||
|         app_module = import_module(app_name) | ||||
|         try: | ||||
|             models = import_module('.models', app_name) | ||||
|             models = import_module('.' + MODELS_MODULE_NAME, app_name) | ||||
|         except ImportError: | ||||
|             self.nesting_level -= 1 | ||||
|             # If the app doesn't have a models module, we can just ignore the | ||||
|             # ImportError and return no models for it. | ||||
|             if not module_has_submodule(app_module, 'models'): | ||||
|             if not module_has_submodule(app_module, MODELS_MODULE_NAME): | ||||
|                 return None | ||||
|             # But if the app does have a models module, we need to figure out | ||||
|             # whether to suppress or propagate the error. If can_postpone is | ||||
|   | ||||
| @@ -24,12 +24,17 @@ Available ``Meta`` options | ||||
|  | ||||
| .. attribute:: Options.app_label | ||||
|  | ||||
|     If a model exists outside of the standard :file:`models.py` (for instance, | ||||
|     if the app's models are in submodules of ``myapp.models``), the model must | ||||
|     define which app it is part of:: | ||||
|     If a model exists outside of the standard locations (:file:`models.py` or | ||||
|     a ``models`` package in an app), the model must define which app it is part | ||||
|     of:: | ||||
|  | ||||
|         app_label = 'myapp' | ||||
|  | ||||
|     .. versionadded:: 1.7 | ||||
|  | ||||
|         ``app_label`` is no longer required for models that are defined | ||||
|         in a ``models`` package within an app. | ||||
|  | ||||
| ``db_table`` | ||||
| ------------ | ||||
|  | ||||
|   | ||||
| @@ -57,6 +57,9 @@ Minor features | ||||
| * The :meth:`QuerySet.update_or_create() | ||||
|   <django.db.models.query.QuerySet.update_or_create>` method was added. | ||||
|  | ||||
| * :attr:`~django.db.models.Options.app_label` is no longer required for models | ||||
|   that are defined in a ``models`` package within an app. | ||||
|  | ||||
| Backwards incompatible changes in 1.7 | ||||
| ===================================== | ||||
|  | ||||
|   | ||||
| @@ -6,6 +6,3 @@ class Article(models.Model): | ||||
|     sites = models.ManyToManyField(Site) | ||||
|     headline = models.CharField(max_length=100) | ||||
|     publications = models.ManyToManyField("model_package.Publication", null=True, blank=True,) | ||||
|  | ||||
|     class Meta: | ||||
|         app_label = 'model_package' | ||||
|   | ||||
| @@ -3,6 +3,3 @@ from django.db import models | ||||
|  | ||||
| class Publication(models.Model): | ||||
|     title = models.CharField(max_length=30) | ||||
|  | ||||
|     class Meta: | ||||
|         app_label = 'model_package' | ||||
|   | ||||
| @@ -14,9 +14,6 @@ class Advertisment(models.Model): | ||||
|         "model_package.Publication", null=True, blank=True | ||||
|     ) | ||||
|  | ||||
|     class Meta: | ||||
|         app_label = 'model_package' | ||||
|  | ||||
|  | ||||
| class ModelPackageTests(TestCase): | ||||
|     def test_model_packages(self): | ||||
|   | ||||
		Reference in New Issue
	
	Block a user