diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index f01edbcb28..ba48ded09a 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -31,6 +31,7 @@ class BaseModelAdmin(object): """Functionality common to both ModelAdmin and InlineAdmin.""" raw_id_fields = () fields = None + exclude = None fieldsets = None form = forms.ModelForm filter_vertical = () @@ -262,9 +263,14 @@ class ModelAdmin(BaseModelAdmin): fields = flatten_fieldsets(self.declared_fieldsets) else: fields = None + if self.exclude is None: + exclude = [] + else: + exclude = self.exclude defaults = { "form": self.form, "fields": fields, + "exclude": exclude + kwargs.get("exclude", []), "formfield_callback": self.formfield_for_dbfield, } defaults.update(kwargs) @@ -780,11 +786,16 @@ class InlineModelAdmin(BaseModelAdmin): fields = flatten_fieldsets(self.declared_fieldsets) else: fields = None + if self.exclude is None: + exclude = [] + else: + exclude = self.exclude defaults = { "form": self.form, "formset": self.formset, "fk_name": self.fk_name, "fields": fields, + "exclude": exclude + kwargs.get("exclude", []), "formfield_callback": self.formfield_for_dbfield, "extra": self.extra, "max_num": self.max_num, diff --git a/docs/ref/contrib/admin.txt b/docs/ref/contrib/admin.txt index ceb33bc40a..da2f8a7e53 100644 --- a/docs/ref/contrib/admin.txt +++ b/docs/ref/contrib/admin.txt @@ -181,6 +181,32 @@ displayed, sequentially, in the form. dictionary key that is within the ``fieldsets`` option, as described in the previous section. +``exclude`` +~~~~~~~~~~~ + +This attribute, if given, should be a list of field names to exclude from the +form. + +For example, let's consider the following model:: + + class Author(models.Model): + name = models.CharField(max_length=100) + title = models.CharField(max_length=3) + birth_date = models.DateField(blank=True, null=True) + +If you want a form for the ``Author`` model that includes only the ``name`` +and ``title`` fields, you would specify ``fields`` or ``exclude`` like this:: + + class AuthorAdmin(admin.ModelAdmin): + fields = ('name', 'title') + + class AuthorAdmin(admin.ModelAdmin): + exclude = ('birth_date',) + +Since the Author model only has three fields, ``name``, ``title``, and +``birth_date``, the forms resulting from the above declarations will contain +exactly the same fields. + ``filter_horizontal`` ~~~~~~~~~~~~~~~~~~~~~ diff --git a/tests/modeltests/model_formsets/models.py b/tests/modeltests/model_formsets/models.py index b215e40af8..3c97931595 100644 --- a/tests/modeltests/model_formsets/models.py +++ b/tests/modeltests/model_formsets/models.py @@ -701,5 +701,4 @@ False >>> formset.is_valid() True - """} diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py index ca97a0cb51..f6fda40cf4 100644 --- a/tests/regressiontests/modeladmin/models.py +++ b/tests/regressiontests/modeladmin/models.py @@ -116,6 +116,23 @@ displayed because you forgot to add it to fields/fielsets ['name'] +# Using `exclude`. + +>>> class BandAdmin(ModelAdmin): +... exclude = ['bio'] +>>> ma = BandAdmin(Band, site) +>>> ma.get_form(request).base_fields.keys() +['name', 'sign_date'] + +# Using `fields` and `exclude`. + +>>> class BandAdmin(ModelAdmin): +... fields = ['name', 'bio'] +... exclude = ['bio'] +>>> ma = BandAdmin(Band, site) +>>> ma.get_form(request).base_fields.keys() +['name'] + If we specify a form, it should use it allowing custom validation to work properly. This won't, however, break any of the admin widgets or media.