From 23c24fc08bd05a4b9371df7837b8819f29142ac5 Mon Sep 17 00:00:00 2001 From: Russell Keith-Magee Date: Sun, 25 Jun 2006 04:24:15 +0000 Subject: [PATCH] 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 --- django/core/management.py | 11 ++++++++--- django/db/models/loading.py | 18 +++++++++++++----- django/db/models/options.py | 5 ++++- 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 '' % 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