diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py index ccb31a7d4d..d0cca0a0ba 100644 --- a/django/contrib/admin/options.py +++ b/django/contrib/admin/options.py @@ -129,6 +129,7 @@ class BaseModelAdmin(object): raw_id_fields = () fields = None fieldsets = None + form = forms.ModelForm filter_vertical = () filter_horizontal = () prepopulated_fields = {} @@ -308,17 +309,12 @@ class ModelAdmin(BaseModelAdmin): """ Returns a Form class for use in the admin add view. This is used by add_view and change_view. - - Note that if you override this method, your form will *not* - automatically get the custom admin widgets. raw_id_fields, fields, - fieldsets, filter_vertical, and filter_horizonal will not apply to - your form. You will have manually specify those widgets. """ if self.declared_fieldsets: fields = flatten_fieldsets(self.declared_fieldsets) else: fields = None - return _modelform_factory(self.model, fields=fields, formfield_callback=self.formfield_for_dbfield) + return _modelform_factory(self.model, form=self.form, fields=fields, formfield_callback=self.formfield_for_dbfield) def get_formsets(self, request, obj=None): for inline in self.inline_instances: @@ -704,7 +700,7 @@ class InlineModelAdmin(BaseModelAdmin): fields = flatten_fieldsets(self.declared_fieldsets) else: fields = None - return _inlineformset_factory(self.parent_model, self.model, fk_name=self.fk_name, fields=fields, formfield_callback=self.formfield_for_dbfield, extra=self.extra) + return _inlineformset_factory(self.parent_model, self.model, form=self.form, fk_name=self.fk_name, fields=fields, formfield_callback=self.formfield_for_dbfield, extra=self.extra) def get_fieldsets(self, request, obj=None): if self.declared_fieldsets: diff --git a/django/newforms/models.py b/django/newforms/models.py index 1e74d8546d..ba756df408 100644 --- a/django/newforms/models.py +++ b/django/newforms/models.py @@ -277,7 +277,7 @@ class ModelForm(BaseModelForm): __metaclass__ = ModelFormMetaclass # XXX: This API *will* change. Use at your own risk. -def _modelform_factory(model, form=BaseForm, fields=None, exclude=None, +def _modelform_factory(model, form=ModelForm, fields=None, exclude=None, formfield_callback=lambda f: f.formfield()): # HACK: we should be able to construct a ModelForm without creating # and passing in a temporary inner class @@ -287,7 +287,7 @@ def _modelform_factory(model, form=BaseForm, fields=None, exclude=None, setattr(Meta, 'fields', fields) setattr(Meta, 'exclude', exclude) class_name = model.__name__ + 'Form' - return ModelFormMetaclass(class_name, (ModelForm,), {'Meta': Meta}, + return ModelFormMetaclass(class_name, (form,), {'Meta': Meta}, formfield_callback=formfield_callback) @@ -360,7 +360,7 @@ class BaseModelFormSet(BaseFormSet): super(BaseModelFormSet, self).add_fields(form, index) # XXX: Use at your own risk. This API *will* change. -def _modelformset_factory(model, form=BaseModelForm, formfield_callback=lambda f: f.formfield(), +def _modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(), formset=BaseModelFormSet, extra=1, can_delete=False, can_order=False, fields=None, exclude=None): @@ -427,7 +427,7 @@ def _get_foreign_key(parent_model, model, fk_name=None): # XXX: This API *will* change. Use at your own risk. -def _inlineformset_factory(parent_model, model, form=BaseModelForm, fk_name=None, +def _inlineformset_factory(parent_model, model, form=ModelForm, fk_name=None, fields=None, exclude=None, extra=3, can_order=False, can_delete=True, formfield_callback=lambda f: f.formfield()): diff --git a/tests/regressiontests/modeladmin/models.py b/tests/regressiontests/modeladmin/models.py index 1036037dfb..5e67c873cd 100644 --- a/tests/regressiontests/modeladmin/models.py +++ b/tests/regressiontests/modeladmin/models.py @@ -4,6 +4,7 @@ from django.db import models class Band(models.Model): name = models.CharField(max_length=100) bio = models.TextField() + sign_date = models.DateField() __test__ = {'API_TESTS': """ @@ -26,7 +27,7 @@ for testing. >>> ma = ModelAdmin(Band, site) >>> ma.get_form(request).base_fields.keys() -['name', 'bio'] +['name', 'bio', 'sign_date'] # form/fields/fieldsets interaction ########################################## @@ -40,9 +41,9 @@ no fields argument, and no fieldsets argument. >>> ma = ModelAdmin(Band, site) >>> ma.get_fieldsets(request) -[(None, {'fields': ['name', 'bio']})] +[(None, {'fields': ['name', 'bio', 'sign_date']})] >>> ma.get_fieldsets(request, band) -[(None, {'fields': ['name', 'bio']})] +[(None, {'fields': ['name', 'bio', 'sign_date']})] If we specify the fields argument, fieldsets_add and fielsets_change should @@ -85,7 +86,24 @@ displayed because you forgot to add it to fields/fielsets ['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. +>>> from django import newforms as forms +>>> class AdminBandForm(forms.ModelForm): +... delete = forms.BooleanField() +... +... class Meta: +... model = Band + +>>> class BandAdmin(ModelAdmin): +... form = AdminBandForm + +>>> ma = BandAdmin(Band, site) +>>> ma.get_form(request).base_fields.keys() +['name', 'bio', 'sign_date', 'delete'] +>>> type(ma.get_form(request).base_fields['sign_date'].widget) + """ }