diff --git a/django/contrib/admin/validation.py b/django/contrib/admin/validation.py index 7814021cf9..f640cc5100 100644 --- a/django/contrib/admin/validation.py +++ b/django/contrib/admin/validation.py @@ -1,7 +1,7 @@ from django.core.exceptions import ImproperlyConfigured from django.db import models -from django.newforms.models import BaseModelForm, BaseModelFormSet +from django.newforms.models import BaseModelForm, BaseModelFormSet, fields_for_model from django.contrib.admin.options import flatten_fieldsets, BaseModelAdmin from django.contrib.admin.options import HORIZONTAL, VERTICAL @@ -144,6 +144,9 @@ def _validate_base(cls, model): 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'): @@ -159,7 +162,7 @@ def _validate_base(cls, model): if cls.fields: # default value is None _check_istuplew('fields', cls.fields) for field in cls.fields: - _check_field_existsw('fields', field) + _check_form_field_existsw('fields', field) if cls.fieldsets: raise ImproperlyConfigured('Both fieldsets and fields are specified in %s.' % cls.__name__) @@ -177,7 +180,7 @@ def _validate_base(cls, model): "%s.fieldsets[%d][1] field options dict." % (cls.__name__, idx)) for field in flatten_fieldsets(cls.fieldsets): - _check_field_existsw("fieldsets[%d][1]['fields']" % idx, field) + _check_form_field_existsw("fieldsets[%d][1]['fields']" % idx, field) # form if hasattr(cls, 'form') and not issubclass(cls.form, BaseModelForm): @@ -250,6 +253,21 @@ def _check_field_exists(cls, model, opts, label, field): "field `%s` that is missing from model `%s`." % (cls.__name__, label, field, model.__name__)) +def _check_form_field_exists(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 " + "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 " + "is missing from the form." % (cls.__name__, label, field)) + def _check_attr_exists(cls, model, opts, label, field): try: return opts.get_field(field) diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py index 5cd27dd3c1..17e3974e1c 100644 --- a/tests/regressiontests/modeladmin/models.py +++ b/tests/regressiontests/modeladmin/models.py @@ -332,7 +332,7 @@ ImproperlyConfigured: `fields` key is required in ValidationTestModelAdmin.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 model `ValidationTestModel`. +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",)}),) @@ -357,6 +357,58 @@ Traceback (most recent call last): ... ImproperlyConfigured: ValidationTestModelAdmin.form does not inherit from BaseModelForm. +# fielsets with custom form + +>>> class BandAdmin(ModelAdmin): +... fieldsets = ( +... ('Band', { +... 'fields': ('non_existent_field',) +... }), +... ) +>>> 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. + +>>> class BandAdmin(ModelAdmin): +... fieldsets = ( +... ('Band', { +... 'fields': ('name',) +... }), +... ) +>>> validate(BandAdmin, Band) + +>>> class AdminBandForm(forms.ModelForm): +... class Meta: +... model = Band +>>> class BandAdmin(ModelAdmin): +... form = AdminBandForm +... +... fieldsets = ( +... ('Band', { +... 'fields': ('non_existent_field',) +... }), +... ) +>>> 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. + +>>> class AdminBandForm(forms.ModelForm): +... delete = forms.BooleanField() +... +... class Meta: +... model = Band +>>> class BandAdmin(ModelAdmin): +... form = AdminBandForm +... +... fieldsets = ( +... ('Band', { +... 'fields': ('name', 'bio', 'sign_date', 'delete') +... }), +... ) +>>> validate(BandAdmin, Band) + # filter_vertical >>> class ValidationTestModelAdmin(ModelAdmin): @@ -736,7 +788,7 @@ ImproperlyConfigured: `ValidationTestInline.fields` must be a list or tuple. >>> validate(ValidationTestModelAdmin, ValidationTestModel) Traceback (most recent call last): ... -ImproperlyConfigured: `ValidationTestInline.fields` refers to field `non_existent_field` that is missing from model `ValidationTestInlineModel`. +ImproperlyConfigured: `ValidationTestInline.fields` refers to field `non_existent_field` that is missing from the form. # fk_name