mirror of
https://github.com/django/django.git
synced 2024-12-23 01:25:58 +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:
parent
fba6c2ede7
commit
2333c9662b
@ -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.deletion import Collector
|
||||||
from django.db.models.options import Options
|
from django.db.models.options import Options
|
||||||
from django.db.models import signals
|
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.translation import ugettext_lazy as _
|
||||||
from django.utils.functional import curry
|
from django.utils.functional import curry
|
||||||
from django.utils.encoding import force_str, force_text
|
from django.utils.encoding import force_str, force_text
|
||||||
@ -86,10 +86,22 @@ class ModelBase(type):
|
|||||||
base_meta = getattr(new_class, '_meta', None)
|
base_meta = getattr(new_class, '_meta', None)
|
||||||
|
|
||||||
if getattr(meta, 'app_label', None) is 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 'django.contrib.sites.models', this would be 'sites'.
|
||||||
|
# For 'geo.models.places' this would be 'geo'.
|
||||||
|
|
||||||
model_module = sys.modules[new_class.__module__]
|
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:
|
else:
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
|
|
||||||
|
@ -15,6 +15,8 @@ import os
|
|||||||
__all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models',
|
__all__ = ('get_apps', 'get_app', 'get_models', 'get_model', 'register_models',
|
||||||
'load_app', 'app_cache_ready')
|
'load_app', 'app_cache_ready')
|
||||||
|
|
||||||
|
MODELS_MODULE_NAME = 'models'
|
||||||
|
|
||||||
|
|
||||||
class UnavailableApp(Exception):
|
class UnavailableApp(Exception):
|
||||||
pass
|
pass
|
||||||
@ -98,12 +100,12 @@ class AppCache(object):
|
|||||||
self.nesting_level += 1
|
self.nesting_level += 1
|
||||||
app_module = import_module(app_name)
|
app_module = import_module(app_name)
|
||||||
try:
|
try:
|
||||||
models = import_module('.models', app_name)
|
models = import_module('.' + MODELS_MODULE_NAME, app_name)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
self.nesting_level -= 1
|
self.nesting_level -= 1
|
||||||
# If the app doesn't have a models module, we can just ignore the
|
# If the app doesn't have a models module, we can just ignore the
|
||||||
# ImportError and return no models for it.
|
# 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
|
return None
|
||||||
# But if the app does have a models module, we need to figure out
|
# 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
|
# whether to suppress or propagate the error. If can_postpone is
|
||||||
|
@ -24,12 +24,17 @@ Available ``Meta`` options
|
|||||||
|
|
||||||
.. attribute:: Options.app_label
|
.. attribute:: Options.app_label
|
||||||
|
|
||||||
If a model exists outside of the standard :file:`models.py` (for instance,
|
If a model exists outside of the standard locations (:file:`models.py` or
|
||||||
if the app's models are in submodules of ``myapp.models``), the model must
|
a ``models`` package in an app), the model must define which app it is part
|
||||||
define which app it is part of::
|
of::
|
||||||
|
|
||||||
app_label = 'myapp'
|
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``
|
``db_table``
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
@ -57,6 +57,9 @@ Minor features
|
|||||||
* The :meth:`QuerySet.update_or_create()
|
* The :meth:`QuerySet.update_or_create()
|
||||||
<django.db.models.query.QuerySet.update_or_create>` method was added.
|
<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
|
Backwards incompatible changes in 1.7
|
||||||
=====================================
|
=====================================
|
||||||
|
|
||||||
|
@ -6,6 +6,3 @@ class Article(models.Model):
|
|||||||
sites = models.ManyToManyField(Site)
|
sites = models.ManyToManyField(Site)
|
||||||
headline = models.CharField(max_length=100)
|
headline = models.CharField(max_length=100)
|
||||||
publications = models.ManyToManyField("model_package.Publication", null=True, blank=True,)
|
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):
|
class Publication(models.Model):
|
||||||
title = models.CharField(max_length=30)
|
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
|
"model_package.Publication", null=True, blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
class Meta:
|
|
||||||
app_label = 'model_package'
|
|
||||||
|
|
||||||
|
|
||||||
class ModelPackageTests(TestCase):
|
class ModelPackageTests(TestCase):
|
||||||
def test_model_packages(self):
|
def test_model_packages(self):
|
||||||
|
Loading…
Reference in New Issue
Block a user