Commits

Anonymous committed 41bb847

Tweaked the admin validation code to make things a bit easier to read. Tracing
through all the underscore-prefixed and wrapped functions was a bit trying and
some of the names were misleading. No functional changes. Primarily, this is
just bringing the style into line with the rest of the codebase.

Comments (0)

Files changed (2)

django/contrib/admin/validation.py

 from django.contrib.admin.options import flatten_fieldsets, BaseModelAdmin
 from django.contrib.admin.options import HORIZONTAL, VERTICAL
 
+__all__ = ['validate']
+
 def validate(cls, model):
     """
     Does basic ModelAdmin option validation. Calls custom validation
     custom validation classmethod should be: def validate(cls, model).
     """
     opts = model._meta
-    _validate_base(cls, model)
-
-    # currying is expensive, use wrappers instead
-    def _check_istuplew(label, obj):
-        _check_istuple(cls, label, obj)
-
-    def _check_isdictw(label, obj):
-        _check_isdict(cls, label, obj)
-
-    def _check_field_existsw(label, field):
-        return _check_field_exists(cls, model, opts, label, field)
-
-    def _check_attr_existsw(label, field):
-        return _check_attr_exists(cls, model, opts, label, field)
+    validate_base(cls, model)
 
     # list_display
     if hasattr(cls, 'list_display'):
-        _check_istuplew('list_display', cls.list_display)
+        check_isseq(cls, 'list_display', cls.list_display)
         for idx, field in enumerate(cls.list_display):
             if not callable(field):
                 if not hasattr(cls, field):
                         try:
                             opts.get_field(field)
                         except models.FieldDoesNotExist:
-                            raise ImproperlyConfigured("%s.list_display[%d], %r is "
-                                "not a callable or an attribute of %r or found in the model %r."
+                            raise ImproperlyConfigured("%s.list_display[%d], %r is not a callable or an attribute of %r or found in the model %r."
                                 % (cls.__name__, idx, field, cls.__name__, model._meta.object_name))
-                        f = _check_attr_existsw("list_display[%d]" % idx, field)
+                        f = fetch_attr(cls, model, opts, "list_display[%d]" % idx, field)
                         if isinstance(f, models.ManyToManyField):
-                            raise ImproperlyConfigured("`%s.list_display[%d]`, `%s` is a "
-                                "ManyToManyField which is not supported."
+                            raise ImproperlyConfigured("'%s.list_display[%d]', '%s' is a ManyToManyField which is not supported."
                                 % (cls.__name__, idx, field))
 
     # list_display_links
     if hasattr(cls, 'list_display_links'):
-        _check_istuplew('list_display_links', cls.list_display_links)
+        check_isseq(cls, 'list_display_links', cls.list_display_links)
         for idx, field in enumerate(cls.list_display_links):
-            _check_attr_existsw('list_display_links[%d]' % idx, field)
+            fetch_attr(cls, model, opts, 'list_display_links[%d]' % idx, field)
             if field not in cls.list_display:
-                raise ImproperlyConfigured("`%s.list_display_links[%d]`"
-                        "refers to `%s` which is not defined in `list_display`."
+                raise ImproperlyConfigured("'%s.list_display_links[%d]'"
+                        "refers to '%s' which is not defined in 'list_display'."
                         % (cls.__name__, idx, field))
 
     # list_filter
     if hasattr(cls, 'list_filter'):
-        _check_istuplew('list_filter', cls.list_filter)
+        check_isseq(cls, 'list_filter', cls.list_filter)
         for idx, field in enumerate(cls.list_filter):
-            _check_field_existsw('list_filter[%d]' % idx, field)
+            get_field(cls, model, opts, 'list_filter[%d]' % idx, field)
 
     # list_per_page = 100
     if hasattr(cls, 'list_per_page') and not isinstance(cls.list_per_page, int):
-        raise ImproperlyConfigured("`%s.list_per_page` should be a integer."
+        raise ImproperlyConfigured("'%s.list_per_page' should be a integer."
                 % cls.__name__)
 
     # search_fields = ()
     if hasattr(cls, 'search_fields'):
-        _check_istuplew('search_fields', cls.search_fields)
-        
+        check_isseq(cls, 'search_fields', cls.search_fields)
+
     # date_hierarchy = None
     if cls.date_hierarchy:
-        f = _check_field_existsw('date_hierarchy', cls.date_hierarchy)
+        f = get_field(cls, model, opts, 'date_hierarchy', cls.date_hierarchy)
         if not isinstance(f, (models.DateField, models.DateTimeField)):
-            raise ImproperlyConfigured("`%s.date_hierarchy is "
+            raise ImproperlyConfigured("'%s.date_hierarchy is "
                     "neither an instance of DateField nor DateTimeField."
                     % cls.__name__)
 
     # ordering = None
     if cls.ordering:
-        _check_istuplew('ordering', cls.ordering)
+        check_isseq(cls, 'ordering', cls.ordering)
         for idx, field in enumerate(cls.ordering):
             if field == '?' and len(cls.ordering) != 1:
-                raise ImproperlyConfigured("`%s.ordering` has the random "
-                        "ordering marker `?`, but contains other fields as "
-                        "well. Please either remove `?` or the other fields."
+                raise ImproperlyConfigured("'%s.ordering' has the random "
+                        "ordering marker '?', but contains other fields as "
+                        "well. Please either remove '?' or the other fields."
                         % cls.__name__)
             if field == '?':
                 continue
             # this format would be nice, but it's a little fiddly).
             if '__' in field:
                 continue
-            _check_field_existsw('ordering[%d]' % idx, field)
+            get_field(cls, model, opts, 'ordering[%d]' % idx, field)
 
     # list_select_related = False
     # save_as = False
     # save_on_top = False
     for attr in ('list_select_related', 'save_as', 'save_on_top'):
         if not isinstance(getattr(cls, attr), bool):
-            raise ImproperlyConfigured("`%s.%s` should be a boolean."
+            raise ImproperlyConfigured("'%s.%s' should be a boolean."
                     % (cls.__name__, attr))
 
     # inlines = []
     if hasattr(cls, 'inlines'):
-        _check_istuplew('inlines', cls.inlines)
+        check_isseq(cls, 'inlines', cls.inlines)
         for idx, inline in enumerate(cls.inlines):
             if not issubclass(inline, BaseModelAdmin):
-                raise ImproperlyConfigured("`%s.inlines[%d]` does not inherit "
+                raise ImproperlyConfigured("'%s.inlines[%d]' does not inherit "
                         "from BaseModelAdmin." % (cls.__name__, idx))
             if not inline.model:
-                raise ImproperlyConfigured("`model` is a required attribute "
-                        "of `%s.inlines[%d]`." % (cls.__name__, idx))
+                raise ImproperlyConfigured("'model' is a required attribute "
+                        "of '%s.inlines[%d]'." % (cls.__name__, idx))
             if not issubclass(inline.model, models.Model):
-                raise ImproperlyConfigured("`%s.inlines[%d].model` does not "
+                raise ImproperlyConfigured("'%s.inlines[%d].model' does not "
                         "inherit from models.Model." % (cls.__name__, idx))
-            _validate_base(inline, inline.model)
-            _validate_inline(inline)
-            
-def _validate_inline(cls):
+            validate_base(inline, inline.model)
+            validate_inline(inline)
+
+def validate_inline(cls):
     # model is already verified to exist and be a Model
     if cls.fk_name: # default value is None
-        f = _check_field_exists(cls, cls.model, cls.model._meta,
+        f = get_field(cls, cls.model, cls.model._meta,
                 'fk_name', cls.fk_name)
         if not isinstance(f, models.ForeignKey):
-            raise ImproperlyConfigured("`%s.fk_name is not an instance of "
+            raise ImproperlyConfigured("'%s.fk_name is not an instance of "
                     "models.ForeignKey." % cls.__name__)
     # extra = 3
     # max_num = 0
     for attr in ('extra', 'max_num'):
         if not isinstance(getattr(cls, attr), int):
-            raise ImproperlyConfigured("`%s.%s` should be a integer."
+            raise ImproperlyConfigured("'%s.%s' should be a integer."
                     % (cls.__name__, attr))
 
     # formset
     if hasattr(cls, 'formset') and not issubclass(cls.formset, BaseModelFormSet):
-        raise ImproperlyConfigured("`%s.formset` does not inherit from "
+        raise ImproperlyConfigured("'%s.formset' does not inherit from "
                 "BaseModelFormSet." % cls.__name__)
 
-def _validate_base(cls, model):
+def validate_base(cls, model):
     opts = model._meta
-    # currying is expensive, use wrappers instead
-    def _check_istuplew(label, obj):
-        _check_istuple(cls, label, obj)
-
-    def _check_isdictw(label, obj):
-        _check_isdict(cls, label, obj)
-
-    def _check_field_existsw(label, field):
-        return _check_field_exists(cls, model, opts, label, field)
-    
-    def _check_form_field_existsw(label, field):
-        return _check_form_field_exists(cls, model, opts, label, field)
 
     # raw_id_fields
     if hasattr(cls, 'raw_id_fields'):
-        _check_istuplew('raw_id_fields', cls.raw_id_fields)
+        check_isseq(cls, 'raw_id_fields', cls.raw_id_fields)
         for idx, field in enumerate(cls.raw_id_fields):
-            f = _check_field_existsw('raw_id_fields', field)
+            f = get_field(cls, model, opts, 'raw_id_fields', field)
             if not isinstance(f, (models.ForeignKey, models.ManyToManyField)):
-                raise ImproperlyConfigured("`%s.raw_id_fields[%d]`, `%s` must "
+                raise ImproperlyConfigured("'%s.raw_id_fields[%d]', '%s' must "
                         "be either a ForeignKey or ManyToManyField."
                         % (cls.__name__, idx, field))
 
     # fields
     if cls.fields: # default value is None
-        _check_istuplew('fields', cls.fields)
+        check_isseq(cls, 'fields', cls.fields)
         for field in cls.fields:
-            _check_form_field_existsw('fields', field)
+            check_formfield(cls, model, opts, 'fields', field)
         if cls.fieldsets:
             raise ImproperlyConfigured('Both fieldsets and fields are specified in %s.' % cls.__name__)
         if len(cls.fields) > len(set(cls.fields)):
 
     # fieldsets
     if cls.fieldsets: # default value is None
-        _check_istuplew('fieldsets', cls.fieldsets)
+        check_isseq(cls, 'fieldsets', cls.fieldsets)
         for idx, fieldset in enumerate(cls.fieldsets):
-            _check_istuplew('fieldsets[%d]' % idx, fieldset)
+            check_isseq(cls, 'fieldsets[%d]' % idx, fieldset)
             if len(fieldset) != 2:
-                raise ImproperlyConfigured("`%s.fieldsets[%d]` does not "
+                raise ImproperlyConfigured("'%s.fieldsets[%d]' does not "
                         "have exactly two elements." % (cls.__name__, idx))
-            _check_isdictw('fieldsets[%d][1]' % idx, fieldset[1])
+            check_isdict(cls, 'fieldsets[%d][1]' % idx, fieldset[1])
             if 'fields' not in fieldset[1]:
-                raise ImproperlyConfigured("`fields` key is required in "
+                raise ImproperlyConfigured("'fields' key is required in "
                         "%s.fieldsets[%d][1] field options dict."
                         % (cls.__name__, idx))
         flattened_fieldsets = flatten_fieldsets(cls.fieldsets)
         if len(flattened_fieldsets) > len(set(flattened_fieldsets)):
             raise ImproperlyConfigured('There are duplicate field(s) in %s.fieldsets' % cls.__name__)
         for field in flattened_fieldsets:
-            _check_form_field_existsw("fieldsets[%d][1]['fields']" % idx, field)
+            check_formfield(cls, model, opts, "fieldsets[%d][1]['fields']" % idx, field)
 
     # form
     if hasattr(cls, 'form') and not issubclass(cls.form, BaseModelForm):
 
     # filter_vertical
     if hasattr(cls, 'filter_vertical'):
-        _check_istuplew('filter_vertical', cls.filter_vertical)
+        check_isseq(cls, 'filter_vertical', cls.filter_vertical)
         for idx, field in enumerate(cls.filter_vertical):
-            f = _check_field_existsw('filter_vertical', field)
+            f = get_field(cls, model, opts, 'filter_vertical', field)
             if not isinstance(f, models.ManyToManyField):
-                raise ImproperlyConfigured("`%s.filter_vertical[%d]` must be "
+                raise ImproperlyConfigured("'%s.filter_vertical[%d]' must be "
                     "a ManyToManyField." % (cls.__name__, idx))
 
     # filter_horizontal
     if hasattr(cls, 'filter_horizontal'):
-        _check_istuplew('filter_horizontal', cls.filter_horizontal)
+        check_isseq(cls, 'filter_horizontal', cls.filter_horizontal)
         for idx, field in enumerate(cls.filter_horizontal):
-            f = _check_field_existsw('filter_horizontal', field)
+            f = get_field(cls, model, opts, 'filter_horizontal', field)
             if not isinstance(f, models.ManyToManyField):
-                raise ImproperlyConfigured("`%s.filter_horizontal[%d]` must be "
+                raise ImproperlyConfigured("'%s.filter_horizontal[%d]' must be "
                     "a ManyToManyField." % (cls.__name__, idx))
 
     # radio_fields
     if hasattr(cls, 'radio_fields'):
-        _check_isdictw('radio_fields', cls.radio_fields)
+        check_isdict(cls, 'radio_fields', cls.radio_fields)
         for field, val in cls.radio_fields.items():
-            f = _check_field_existsw('radio_fields', field)
+            f = get_field(cls, model, opts, 'radio_fields', field)
             if not (isinstance(f, models.ForeignKey) or f.choices):
-                raise ImproperlyConfigured("`%s.radio_fields['%s']` "
+                raise ImproperlyConfigured("'%s.radio_fields['%s']' "
                         "is neither an instance of ForeignKey nor does "
                         "have choices set." % (cls.__name__, field))
             if not val in (HORIZONTAL, VERTICAL):
-                raise ImproperlyConfigured("`%s.radio_fields['%s']` "
+                raise ImproperlyConfigured("'%s.radio_fields['%s']' "
                         "is neither admin.HORIZONTAL nor admin.VERTICAL."
                         % (cls.__name__, field))
 
     # prepopulated_fields
     if hasattr(cls, 'prepopulated_fields'):
-        _check_isdictw('prepopulated_fields', cls.prepopulated_fields)
+        check_isdict(cls, 'prepopulated_fields', cls.prepopulated_fields)
         for field, val in cls.prepopulated_fields.items():
-            f = _check_field_existsw('prepopulated_fields', field)
+            f = get_field(cls, model, opts, 'prepopulated_fields', field)
             if isinstance(f, (models.DateTimeField, models.ForeignKey,
                 models.ManyToManyField)):
-                raise ImproperlyConfigured("`%s.prepopulated_fields['%s']` "
+                raise ImproperlyConfigured("'%s.prepopulated_fields['%s']' "
                         "is either a DateTimeField, ForeignKey or "
                         "ManyToManyField. This isn't allowed."
                         % (cls.__name__, field))
-            _check_istuplew("prepopulated_fields['%s']" % field, val)
+            check_isseq(cls, "prepopulated_fields['%s']" % field, val)
             for idx, f in enumerate(val):
-                _check_field_existsw("prepopulated_fields['%s'][%d]"
+                get_field(cls, model,
+                        opts, "prepopulated_fields['%s'][%d]"
                         % (f, idx), f)
 
-def _check_istuple(cls, label, obj):
+def check_isseq(cls, label, obj):
     if not isinstance(obj, (list, tuple)):
-        raise ImproperlyConfigured("`%s.%s` must be a "
-                "list or tuple." % (cls.__name__, label))
-
-def _check_isdict(cls, label, obj):
-    if not isinstance(obj, dict):
-        raise ImproperlyConfigured("`%s.%s` must be a dictionary."
+        raise ImproperlyConfigured("'%s.%s' must be a list or tuple."
                 % (cls.__name__, label))
 
-def _check_field_exists(cls, model, opts, label, field):
+def check_isdict(cls, label, obj):
+    if not isinstance(obj, dict):
+        raise ImproperlyConfigured("'%s.%s' must be a dictionary."
+                % (cls.__name__, label))
+
+def get_field(cls, model, opts, label, field):
     try:
         return opts.get_field(field)
     except models.FieldDoesNotExist:
-        raise ImproperlyConfigured("`%s.%s` refers to "
-                "field `%s` that is missing from model `%s`."
+        raise ImproperlyConfigured("'%s.%s' refers to field '%s' that is missing from model '%s'."
                 % (cls.__name__, label, field, model.__name__))
 
-def _check_form_field_exists(cls, model, opts, label, field):
+def check_formfield(cls, model, opts, label, field):
     if hasattr(cls.form, 'base_fields'):
         try:
             cls.form.base_fields[field]
         except KeyError:
-            raise ImproperlyConfigured("`%s.%s` refers to field `%s` that "
+            raise ImproperlyConfigured("'%s.%s' refers to field '%s' that "
                 "is missing from the form." % (cls.__name__, label, field))
     else:
         fields = fields_for_model(model)
         try:
             fields[field]
         except KeyError:
-            raise ImproperlyConfigured("`%s.%s` refers to field `%s` that "
+            raise ImproperlyConfigured("'%s.%s' refers to field '%s' that "
                 "is missing from the form." % (cls.__name__, label, field))
 
-def _check_attr_exists(cls, model, opts, label, field):
+def fetch_attr(cls, model, opts, label, field):
     try:
         return opts.get_field(field)
     except models.FieldDoesNotExist:
-        if not hasattr(model, field):
-            raise ImproperlyConfigured("`%s.%s` refers to "
-                    "`%s` that is neither a field, method or property "
-                    "of model `%s`."
-                    % (cls.__name__, label, field, model.__name__))
+        pass
+    try:
         return getattr(model, field)
+    except AttributeError:
+        raise ImproperlyConfigured("'%s.%s' refers to '%s' that is neither a field, method or property of model '%s'."
+            % (cls.__name__, label, field, model.__name__))

tests/regressiontests/modeladmin/models.py

 >>> site.register(ValidationTestModel, ValidationTestModelAdmin)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.raw_id_fields` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.raw_id_fields' must be a list or tuple.
 
 >>> settings.DEBUG = False
 
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.raw_id_fields` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.raw_id_fields' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     raw_id_fields = ('non_existent_field',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.raw_id_fields` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.raw_id_fields' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     raw_id_fields = ('name',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.raw_id_fields[0]`, `name` must be either a ForeignKey or ManyToManyField.
+ImproperlyConfigured: 'ValidationTestModelAdmin.raw_id_fields[0]', 'name' must be either a ForeignKey or ManyToManyField.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     raw_id_fields = ('users',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.fieldsets` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.fieldsets' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     fieldsets = ({},)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.fieldsets[0]` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.fieldsets[0]' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     fieldsets = ((),)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.fieldsets[0]` does not have exactly two elements.
+ImproperlyConfigured: 'ValidationTestModelAdmin.fieldsets[0]' does not have exactly two elements.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     fieldsets = (("General", ()),)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.fieldsets[0][1]` must be a dictionary.
+ImproperlyConfigured: 'ValidationTestModelAdmin.fieldsets[0][1]' must be a dictionary.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     fieldsets = (("General", {}),)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `fields` key is required in ValidationTestModelAdmin.fieldsets[0][1] field options dict.
+ImproperlyConfigured: 'fields' key is required in ValidationTestModelAdmin.fieldsets[0][1] field options dict.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     fieldsets = (("General", {"fields": ("non_existent_field",)}),)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.fieldsets[0][1]['fields']` refers to field `non_existent_field` that is missing from the form.
+ImproperlyConfigured: 'ValidationTestModelAdmin.fieldsets[0][1]['fields']' refers to field 'non_existent_field' that is missing from the form.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     fieldsets = (("General", {"fields": ("name",)}),)
 >>> validate(BandAdmin, Band)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `BandAdmin.fieldsets[0][1]['fields']` refers to field `non_existent_field` that is missing from the form.
+ImproperlyConfigured: 'BandAdmin.fieldsets[0][1]['fields']' refers to field 'non_existent_field' that is missing from the form.
 
 >>> class BandAdmin(ModelAdmin):
 ...     fieldsets = (
 >>> validate(BandAdmin, Band)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `BandAdmin.fieldsets[0][1]['fields']` refers to field `non_existent_field` that is missing from the form.
+ImproperlyConfigured: 'BandAdmin.fieldsets[0][1]['fields']' refers to field 'non_existent_field' that is missing from the form.
 
 >>> class AdminBandForm(forms.ModelForm):
 ...     delete = forms.BooleanField()
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.filter_vertical` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.filter_vertical' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     filter_vertical = ("non_existent_field",)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.filter_vertical` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.filter_vertical' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     filter_vertical = ("name",)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.filter_vertical[0]` must be a ManyToManyField.
+ImproperlyConfigured: 'ValidationTestModelAdmin.filter_vertical[0]' must be a ManyToManyField.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     filter_vertical = ("users",)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.filter_horizontal` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.filter_horizontal' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     filter_horizontal = ("non_existent_field",)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.filter_horizontal` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.filter_horizontal' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     filter_horizontal = ("name",)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.filter_horizontal[0]` must be a ManyToManyField.
+ImproperlyConfigured: 'ValidationTestModelAdmin.filter_horizontal[0]' must be a ManyToManyField.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     filter_horizontal = ("users",)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.radio_fields` must be a dictionary.
+ImproperlyConfigured: 'ValidationTestModelAdmin.radio_fields' must be a dictionary.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     radio_fields = {"non_existent_field": None}
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.radio_fields` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.radio_fields' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     radio_fields = {"name": None}
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.radio_fields['name']` is neither an instance of ForeignKey nor does have choices set.
+ImproperlyConfigured: 'ValidationTestModelAdmin.radio_fields['name']' is neither an instance of ForeignKey nor does have choices set.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     radio_fields = {"state": None}
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.radio_fields['state']` is neither admin.HORIZONTAL nor admin.VERTICAL.
+ImproperlyConfigured: 'ValidationTestModelAdmin.radio_fields['state']' is neither admin.HORIZONTAL nor admin.VERTICAL.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     radio_fields = {"state": VERTICAL}
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.prepopulated_fields` must be a dictionary.
+ImproperlyConfigured: 'ValidationTestModelAdmin.prepopulated_fields' must be a dictionary.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     prepopulated_fields = {"non_existent_field": None}
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.prepopulated_fields` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.prepopulated_fields' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     prepopulated_fields = {"slug": ("non_existent_field",)}
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.prepopulated_fields['non_existent_field'][0]` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.prepopulated_fields['non_existent_field'][0]' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     prepopulated_fields = {"users": ("name",)}
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.prepopulated_fields['users']` is either a DateTimeField, ForeignKey or ManyToManyField. This isn't allowed.
+ImproperlyConfigured: 'ValidationTestModelAdmin.prepopulated_fields['users']' is either a DateTimeField, ForeignKey or ManyToManyField. This isn't allowed.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     prepopulated_fields = {"slug": ("name",)}
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_display` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_display' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_display = ('non_existent_field',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_display[0]`, `users` is a ManyToManyField which is not supported.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_display[0]', 'users' is a ManyToManyField which is not supported.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_display = ('name',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_display_links` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_display_links' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_display_links = ('non_existent_field',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_display_links[0]` refers to `non_existent_field` that is neither a field, method or property of model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_display_links[0]' refers to 'non_existent_field' that is neither a field, method or property of model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_display_links = ('name',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_display_links[0]`refers to `name` which is not defined in `list_display`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_display_links[0]'refers to 'name' which is not defined in 'list_display'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_display = ('name',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_filter` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_filter' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_filter = ('non_existent_field',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_filter[0]` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_filter[0]' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_filter = ('is_active',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_per_page` should be a integer.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_per_page' should be a integer.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_per_page = 100
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.search_fields` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.search_fields' must be a list or tuple.
 
 # date_hierarchy
 
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.date_hierarchy` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.date_hierarchy' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     date_hierarchy = 'name'
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.date_hierarchy is neither an instance of DateField nor DateTimeField.
+ImproperlyConfigured: 'ValidationTestModelAdmin.date_hierarchy is neither an instance of DateField nor DateTimeField.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     date_hierarchy = 'pub_date'
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.ordering` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.ordering' must be a list or tuple.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     ordering = ('non_existent_field',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.ordering[0]` refers to field `non_existent_field` that is missing from model `ValidationTestModel`.
+ImproperlyConfigured: 'ValidationTestModelAdmin.ordering[0]' refers to field 'non_existent_field' that is missing from model 'ValidationTestModel'.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     ordering = ('?', 'name')
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.ordering` has the random ordering marker `?`, but contains other fields as well. Please either remove `?` or the other fields.
+ImproperlyConfigured: 'ValidationTestModelAdmin.ordering' has the random ordering marker '?', but contains other fields as well. Please either remove '?' or the other fields.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     ordering = ('?',)
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.list_select_related` should be a boolean.
+ImproperlyConfigured: 'ValidationTestModelAdmin.list_select_related' should be a boolean.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     list_select_related = False
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.save_as` should be a boolean.
+ImproperlyConfigured: 'ValidationTestModelAdmin.save_as' should be a boolean.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     save_as = True
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.save_on_top` should be a boolean.
+ImproperlyConfigured: 'ValidationTestModelAdmin.save_on_top' should be a boolean.
 
 >>> class ValidationTestModelAdmin(ModelAdmin):
 ...     save_on_top = True
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.inlines` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestModelAdmin.inlines' must be a list or tuple.
 
 >>> class ValidationTestInline(object):
 ...     pass
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.inlines[0]` does not inherit from BaseModelAdmin.
+ImproperlyConfigured: 'ValidationTestModelAdmin.inlines[0]' does not inherit from BaseModelAdmin.
 
 >>> class ValidationTestInline(TabularInline):
 ...     pass
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `model` is a required attribute of `ValidationTestModelAdmin.inlines[0]`.
+ImproperlyConfigured: 'model' is a required attribute of 'ValidationTestModelAdmin.inlines[0]'.
 
 >>> class SomethingBad(object):
 ...     pass
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestModelAdmin.inlines[0].model` does not inherit from models.Model.
+ImproperlyConfigured: 'ValidationTestModelAdmin.inlines[0].model' does not inherit from models.Model.
 
 >>> class ValidationTestInline(TabularInline):
 ...     model = ValidationTestInlineModel
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestInline.fields` must be a list or tuple.
+ImproperlyConfigured: 'ValidationTestInline.fields' must be a list or tuple.
 
 >>> class ValidationTestInline(TabularInline):
 ...     model = ValidationTestInlineModel
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestInline.fields` refers to field `non_existent_field` that is missing from the form.
+ImproperlyConfigured: 'ValidationTestInline.fields' refers to field 'non_existent_field' that is missing from the form.
 
 # fk_name
 
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestInline.fk_name` refers to field `non_existent_field` that is missing from model `ValidationTestInlineModel`.
+ImproperlyConfigured: 'ValidationTestInline.fk_name' refers to field 'non_existent_field' that is missing from model 'ValidationTestInlineModel'.
 
 >>> class ValidationTestInline(TabularInline):
 ...     model = ValidationTestInlineModel
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestInline.extra` should be a integer.
+ImproperlyConfigured: 'ValidationTestInline.extra' should be a integer.
 
 >>> class ValidationTestInline(TabularInline):
 ...     model = ValidationTestInlineModel
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestInline.max_num` should be a integer.
+ImproperlyConfigured: 'ValidationTestInline.max_num' should be a integer.
 
 >>> class ValidationTestInline(TabularInline):
 ...     model = ValidationTestInlineModel
 >>> validate(ValidationTestModelAdmin, ValidationTestModel)
 Traceback (most recent call last):
 ...
-ImproperlyConfigured: `ValidationTestInline.formset` does not inherit from BaseModelFormSet.
+ImproperlyConfigured: 'ValidationTestInline.formset' does not inherit from BaseModelFormSet.
 
 >>> class RealModelFormSet(BaseModelFormSet):
 ...     pass