mirror of https://github.com/django/django.git
Fixed #15866, #15850 -- Prevented get_model() and get_models() from returning not-installed models (by default). Thanks adsva for report.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@16053 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
fda8a9a390
commit
6bdaef26ec
|
@ -90,7 +90,8 @@ class ContentType(models.Model):
|
||||||
def model_class(self):
|
def model_class(self):
|
||||||
"Returns the Python model class for this type of content."
|
"Returns the Python model class for this type of content."
|
||||||
from django.db import models
|
from django.db import models
|
||||||
return models.get_model(self.app_label, self.model)
|
return models.get_model(self.app_label, self.model,
|
||||||
|
only_installed=False)
|
||||||
|
|
||||||
def get_object_for_this_type(self, **kwargs):
|
def get_object_for_this_type(self, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -88,7 +88,8 @@ class ModelBase(type):
|
||||||
new_class._base_manager = new_class._base_manager._copy_to_model(new_class)
|
new_class._base_manager = new_class._base_manager._copy_to_model(new_class)
|
||||||
|
|
||||||
# Bail out early if we have already created this class.
|
# Bail out early if we have already created this class.
|
||||||
m = get_model(new_class._meta.app_label, name, False)
|
m = get_model(new_class._meta.app_label, name,
|
||||||
|
seed_cache=False, only_installed=False)
|
||||||
if m is not None:
|
if m is not None:
|
||||||
return m
|
return m
|
||||||
|
|
||||||
|
@ -201,7 +202,8 @@ class ModelBase(type):
|
||||||
# the first time this model tries to register with the framework. There
|
# the first time this model tries to register with the framework. There
|
||||||
# should only be one class for each model, so we always return the
|
# should only be one class for each model, so we always return the
|
||||||
# registered version.
|
# registered version.
|
||||||
return get_model(new_class._meta.app_label, name, False)
|
return get_model(new_class._meta.app_label, name,
|
||||||
|
seed_cache=False, only_installed=False)
|
||||||
|
|
||||||
def copy_managers(cls, base_managers):
|
def copy_managers(cls, base_managers):
|
||||||
# This is in-place sorting of an Options attribute, but that's fine.
|
# This is in-place sorting of an Options attribute, but that's fine.
|
||||||
|
|
|
@ -67,7 +67,8 @@ def add_lazy_relation(cls, field, relation, operation):
|
||||||
# string right away. If get_model returns None, it means that the related
|
# string right away. If get_model returns None, it means that the related
|
||||||
# model isn't loaded yet, so we need to pend the relation until the class
|
# model isn't loaded yet, so we need to pend the relation until the class
|
||||||
# is prepared.
|
# is prepared.
|
||||||
model = get_model(app_label, model_name, False)
|
model = get_model(app_label, model_name,
|
||||||
|
seed_cache=False, only_installed=False)
|
||||||
if model:
|
if model:
|
||||||
operation(field, model, cls)
|
operation(field, model, cls)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -25,7 +25,11 @@ class AppCache(object):
|
||||||
# Keys of app_store are the model modules for each application.
|
# Keys of app_store are the model modules for each application.
|
||||||
app_store = SortedDict(),
|
app_store = SortedDict(),
|
||||||
|
|
||||||
|
# Mapping of installed app_labels to model modules for that app.
|
||||||
|
app_labels = {},
|
||||||
|
|
||||||
# Mapping of app_labels to a dictionary of model names to model code.
|
# Mapping of app_labels to a dictionary of model names to model code.
|
||||||
|
# May contain apps that are not installed.
|
||||||
app_models = SortedDict(),
|
app_models = SortedDict(),
|
||||||
|
|
||||||
# Mapping of app_labels to errors raised when trying to import the app.
|
# Mapping of app_labels to errors raised when trying to import the app.
|
||||||
|
@ -66,6 +70,13 @@ class AppCache(object):
|
||||||
finally:
|
finally:
|
||||||
self.write_lock.release()
|
self.write_lock.release()
|
||||||
|
|
||||||
|
def _label_for(self, app_mod):
|
||||||
|
"""
|
||||||
|
Return app_label for given models module.
|
||||||
|
|
||||||
|
"""
|
||||||
|
return app_mod.__name__.split('.')[-2]
|
||||||
|
|
||||||
def load_app(self, app_name, can_postpone=False):
|
def load_app(self, app_name, can_postpone=False):
|
||||||
"""
|
"""
|
||||||
Loads the app with the provided fully qualified name, and returns the
|
Loads the app with the provided fully qualified name, and returns the
|
||||||
|
@ -99,6 +110,7 @@ class AppCache(object):
|
||||||
self.nesting_level -= 1
|
self.nesting_level -= 1
|
||||||
if models not in self.app_store:
|
if models not in self.app_store:
|
||||||
self.app_store[models] = len(self.app_store)
|
self.app_store[models] = len(self.app_store)
|
||||||
|
self.app_labels[self._label_for(models)] = models
|
||||||
return models
|
return models
|
||||||
|
|
||||||
def app_cache_ready(self):
|
def app_cache_ready(self):
|
||||||
|
@ -146,7 +158,8 @@ class AppCache(object):
|
||||||
self._populate()
|
self._populate()
|
||||||
return self.app_errors
|
return self.app_errors
|
||||||
|
|
||||||
def get_models(self, app_mod=None, include_auto_created=False, include_deferred=False):
|
def get_models(self, app_mod=None,
|
||||||
|
include_auto_created=False, include_deferred=False):
|
||||||
"""
|
"""
|
||||||
Given a module containing models, returns a list of the models.
|
Given a module containing models, returns a list of the models.
|
||||||
Otherwise returns a list of all installed models.
|
Otherwise returns a list of all installed models.
|
||||||
|
@ -166,20 +179,26 @@ class AppCache(object):
|
||||||
pass
|
pass
|
||||||
self._populate()
|
self._populate()
|
||||||
if app_mod:
|
if app_mod:
|
||||||
app_list = [self.app_models.get(app_mod.__name__.split('.')[-2], SortedDict())]
|
if app_mod in self.app_store:
|
||||||
|
app_list = [self.app_models.get(self._label_for(app_mod),
|
||||||
|
SortedDict())]
|
||||||
|
else:
|
||||||
|
app_list = []
|
||||||
else:
|
else:
|
||||||
app_list = self.app_models.itervalues()
|
app_list = [self.app_models.get(app_label, SortedDict())
|
||||||
|
for app_label in self.app_labels.iterkeys()]
|
||||||
model_list = []
|
model_list = []
|
||||||
for app in app_list:
|
for app in app_list:
|
||||||
model_list.extend(
|
model_list.extend(
|
||||||
model for model in app.values()
|
model for model in app.values()
|
||||||
if ((not model._deferred or include_deferred)
|
if ((not model._deferred or include_deferred) and
|
||||||
and (not model._meta.auto_created or include_auto_created))
|
(not model._meta.auto_created or include_auto_created))
|
||||||
)
|
)
|
||||||
self._get_models_cache[cache_key] = model_list
|
self._get_models_cache[cache_key] = model_list
|
||||||
return model_list
|
return model_list
|
||||||
|
|
||||||
def get_model(self, app_label, model_name, seed_cache=True):
|
def get_model(self, app_label, model_name,
|
||||||
|
seed_cache=True, only_installed=True):
|
||||||
"""
|
"""
|
||||||
Returns the model matching the given app_label and case-insensitive
|
Returns the model matching the given app_label and case-insensitive
|
||||||
model_name.
|
model_name.
|
||||||
|
@ -188,6 +207,8 @@ class AppCache(object):
|
||||||
"""
|
"""
|
||||||
if seed_cache:
|
if seed_cache:
|
||||||
self._populate()
|
self._populate()
|
||||||
|
if only_installed and app_label not in self.app_labels:
|
||||||
|
return None
|
||||||
return self.app_models.get(app_label, SortedDict()).get(model_name.lower())
|
return self.app_models.get(app_label, SortedDict()).get(model_name.lower())
|
||||||
|
|
||||||
def register_models(self, app_label, *models):
|
def register_models(self, app_label, *models):
|
||||||
|
|
|
@ -1023,7 +1023,11 @@ class ManageValidate(AdminScriptTestCase):
|
||||||
def test_app_with_import(self):
|
def test_app_with_import(self):
|
||||||
"manage.py validate does not raise errors when an app imports a base class that itself has an abstract base"
|
"manage.py validate does not raise errors when an app imports a base class that itself has an abstract base"
|
||||||
self.write_settings('settings.py',
|
self.write_settings('settings.py',
|
||||||
apps=['admin_scripts.app_with_import', 'django.contrib.comments'],
|
apps=['admin_scripts.app_with_import',
|
||||||
|
'django.contrib.comments',
|
||||||
|
'django.contrib.auth',
|
||||||
|
'django.contrib.contenttypes',
|
||||||
|
'django.contrib.sites'],
|
||||||
sdict={'DEBUG': True})
|
sdict={'DEBUG': True})
|
||||||
args = ['validate']
|
args = ['validate']
|
||||||
out, err = self.run_manage(args)
|
out, err = self.run_manage(args)
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class NotInstalledModel(models.Model):
|
||||||
|
pass
|
|
@ -4,7 +4,7 @@ import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
from django.conf import Settings
|
from django.conf import Settings
|
||||||
from django.db.models.loading import cache, load_app
|
from django.db.models.loading import cache, load_app, get_model, get_models
|
||||||
from django.utils.unittest import TestCase
|
from django.utils.unittest import TestCase
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,3 +81,24 @@ class EggLoadingTest(TestCase):
|
||||||
# Make sure the message is indicating the actual
|
# Make sure the message is indicating the actual
|
||||||
# problem in the broken app.
|
# problem in the broken app.
|
||||||
self.assertTrue("modelz" in e.args[0])
|
self.assertTrue("modelz" in e.args[0])
|
||||||
|
|
||||||
|
|
||||||
|
class GetModelsTest(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
import not_installed.models
|
||||||
|
self.not_installed_module = not_installed.models
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_model_only_returns_installed_models(self):
|
||||||
|
self.assertEqual(
|
||||||
|
get_model("not_installed", "NotInstalledModel"), None)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_models_only_returns_installed_models(self):
|
||||||
|
self.assertFalse(
|
||||||
|
"NotInstalledModel" in
|
||||||
|
[m.__name__ for m in get_models()])
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_models_with_app_label_only_returns_installed_models(self):
|
||||||
|
self.assertEqual(get_models(self.not_installed_module), [])
|
||||||
|
|
Loading…
Reference in New Issue