summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell Keith-Magee <russell@keith-magee.com>2006-06-25 04:24:15 +0000
committerRussell Keith-Magee <russell@keith-magee.com>2006-06-25 04:24:15 +0000
commit23c24fc08bd05a4b9371df7837b8819f29142ac5 (patch)
tree05db6d5fa0e97a1de8738712363aa239f428d67a
parentdc473309ef15e88a41845a52485eb6d38f819637 (diff)
Fixes #1812 -- Added model validity checks to ensure that models.py exists, and has been successfully imported for all INSTALLED_APPS. Previous behaviour was to silently ignore empty/problem models, which resulted in the display of an admin page that doesn't display a supposedly installed model. Thanks to Ian Holsman for the original report.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@3201 bcc190cf-cafb-0310-a4f2-bffc1f526a37
-rw-r--r--django/core/management.py11
-rw-r--r--django/db/models/loading.py18
-rw-r--r--django/db/models/options.py5
3 files changed, 25 insertions, 9 deletions
diff --git a/django/core/management.py b/django/core/management.py
index ea572729d9..948a045aeb 100644
--- a/django/core/management.py
+++ b/django/core/management.py
@@ -803,9 +803,9 @@ class ModelErrorCollection:
self.errors = []
self.outfile = outfile
- def add(self, opts, error):
- self.errors.append((opts, error))
- self.outfile.write(style.ERROR("%s.%s: %s\n" % (opts.app_label, opts.module_name, error)))
+ def add(self, context, error):
+ self.errors.append((context, error))
+ self.outfile.write(style.ERROR("%s: %s\n" % (context, error)))
def get_validation_errors(outfile, app=None):
"""
@@ -814,9 +814,14 @@ def get_validation_errors(outfile, app=None):
Returns number of errors.
"""
from django.db import models
+ from django.db.models.loading import get_app_errors
from django.db.models.fields.related import RelatedObject
e = ModelErrorCollection(outfile)
+
+ for (app_name, error) in get_app_errors().items():
+ e.add(app_name, error)
+
for cls in models.get_models(app):
opts = cls._meta
diff --git a/django/db/models/loading.py b/django/db/models/loading.py
index 4eafc22fb4..96e864cffc 100644
--- a/django/db/models/loading.py
+++ b/django/db/models/loading.py
@@ -10,6 +10,9 @@ _app_list = [] # Cache of installed apps.
_app_models = {} # Dictionary of models against app label
# Each value is a dictionary of model name: model class
# Applabel and Model entry exists in cache when individual model is loaded.
+_app_errors = {} # Dictionary of errors that were experienced when loading the INSTALLED_APPS
+ # Key is the app_name of the model, value is the exception that was raised
+ # during model loading.
_loaded = False # Has the contents of settings.INSTALLED_APPS been loaded?
# i.e., has get_apps() been called?
@@ -22,11 +25,9 @@ def get_apps():
for app_name in settings.INSTALLED_APPS:
try:
load_app(app_name)
- except ImportError:
- pass # Assume this app doesn't have a models.py in it.
- # GOTCHA: It may have a models.py that raises ImportError.
- except AttributeError:
- pass # This app doesn't have a models.py in it.
+ except Exception, e:
+ # Problem importing the app
+ _app_errors[app_name] = e
return _app_list
def get_app(app_label):
@@ -39,10 +40,17 @@ def get_app(app_label):
def load_app(app_name):
"Loads the app with the provided fully qualified name, and returns the model module."
+ global _app_list
mod = __import__(app_name, '', '', ['models'])
if mod.models not in _app_list:
_app_list.append(mod.models)
return mod.models
+
+def get_app_errors():
+ "Returns the map of known problems with the INSTALLED_APPS"
+ global _app_errors
+ get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
+ return _app_errors
def get_models(app_mod=None):
"""
diff --git a/django/db/models/options.py b/django/db/models/options.py
index f8149bdf5c..46a321f170 100644
--- a/django/db/models/options.py
+++ b/django/db/models/options.py
@@ -87,7 +87,10 @@ class Options(object):
def __repr__(self):
return '<Options for %s>' % self.object_name
-
+
+ def __str__(self):
+ return "%s.%s" % (self.app_label, self.module_name)
+
def get_field(self, name, many_to_many=True):
"Returns the requested field by name. Raises FieldDoesNotExist on error."
to_search = many_to_many and (self.fields + self.many_to_many) or self.fields