Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixes #1812 -- Added model validity checks to ensure that models.py e…

…xists, 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
  • Loading branch information...
commit 23c24fc08bd05a4b9371df7837b8819f29142ac5 1 parent dc47330
Russell Keith-Magee authored June 25, 2006
11  django/core/management.py
@@ -803,9 +803,9 @@ def __init__(self, outfile=sys.stdout):
803 803
         self.errors = []
804 804
         self.outfile = outfile
805 805
 
806  
-    def add(self, opts, error):
807  
-        self.errors.append((opts, error))
808  
-        self.outfile.write(style.ERROR("%s.%s: %s\n" % (opts.app_label, opts.module_name, error)))
  806
+    def add(self, context, error):
  807
+        self.errors.append((context, error))
  808
+        self.outfile.write(style.ERROR("%s: %s\n" % (context, error)))
809 809
 
810 810
 def get_validation_errors(outfile, app=None):
811 811
     """
@@ -814,9 +814,14 @@ def get_validation_errors(outfile, app=None):
814 814
     Returns number of errors.
815 815
     """
816 816
     from django.db import models
  817
+    from django.db.models.loading import get_app_errors
817 818
     from django.db.models.fields.related import RelatedObject
818 819
 
819 820
     e = ModelErrorCollection(outfile)
  821
+    
  822
+    for (app_name, error) in get_app_errors().items():
  823
+        e.add(app_name, error)
  824
+        
820 825
     for cls in models.get_models(app):
821 826
         opts = cls._meta
822 827
 
18  django/db/models/loading.py
@@ -10,6 +10,9 @@
10 10
 _app_models = {} # Dictionary of models against app label
11 11
                  # Each value is a dictionary of model name: model class
12 12
                  # Applabel and Model entry exists in cache when individual model is loaded.
  13
+_app_errors = {} # Dictionary of errors that were experienced when loading the INSTALLED_APPS
  14
+                 # Key is the app_name of the model, value is the exception that was raised
  15
+                 # during model loading.
13 16
 _loaded = False  # Has the contents of settings.INSTALLED_APPS been loaded? 
14 17
                  # i.e., has get_apps() been called?
15 18
 
@@ -22,11 +25,9 @@ def get_apps():
22 25
         for app_name in settings.INSTALLED_APPS:
23 26
             try:
24 27
                 load_app(app_name)
25  
-            except ImportError:
26  
-                pass # Assume this app doesn't have a models.py in it.
27  
-                     # GOTCHA: It may have a models.py that raises ImportError.
28  
-            except AttributeError:
29  
-                pass # This app doesn't have a models.py in it.
  28
+            except Exception, e:
  29
+                # Problem importing the app
  30
+                _app_errors[app_name] = e
30 31
     return _app_list
31 32
 
32 33
 def get_app(app_label):
@@ -39,10 +40,17 @@ def get_app(app_label):
39 40
 
40 41
 def load_app(app_name):
41 42
     "Loads the app with the provided fully qualified name, and returns the model module."
  43
+    global _app_list
42 44
     mod = __import__(app_name, '', '', ['models'])
43 45
     if mod.models not in _app_list:
44 46
         _app_list.append(mod.models)
45 47
     return mod.models
  48
+
  49
+def get_app_errors():
  50
+    "Returns the map of known problems with the INSTALLED_APPS"
  51
+    global _app_errors
  52
+    get_apps() # Run get_apps() to populate the _app_list cache. Slightly hackish.
  53
+    return _app_errors
46 54
     
47 55
 def get_models(app_mod=None):
48 56
     """
5  django/db/models/options.py
@@ -87,7 +87,10 @@ def add_field(self, field):
87 87
 
88 88
     def __repr__(self):
89 89
         return '<Options for %s>' % self.object_name
90  
-
  90
+        
  91
+    def __str__(self):
  92
+        return "%s.%s" % (self.app_label, self.module_name)
  93
+        
91 94
     def get_field(self, name, many_to_many=True):
92 95
         "Returns the requested field by name. Raises FieldDoesNotExist on error."
93 96
         to_search = many_to_many and (self.fields + self.many_to_many) or self.fields

0 notes on commit 23c24fc

Please sign in to comment.
Something went wrong with that request. Please try again.