diff --git a/django/forms/models.py b/django/forms/models.py index be9e63d144..4422882315 100644 --- a/django/forms/models.py +++ b/django/forms/models.py @@ -209,7 +209,13 @@ class ModelFormOptions(object): class ModelFormMetaclass(DeclarativeFieldsMetaclass): def __new__(mcs, name, bases, attrs): - formfield_callback = attrs.pop('formfield_callback', None) + base_formfield_callback = None + for b in bases: + if hasattr(b, 'Meta') and hasattr(b.Meta, 'formfield_callback'): + base_formfield_callback = b.Meta.formfield_callback + break + + formfield_callback = attrs.pop('formfield_callback', base_formfield_callback) new_class = super(ModelFormMetaclass, mcs).__new__(mcs, name, bases, attrs) @@ -530,7 +536,8 @@ def modelform_factory(model, form=ModelForm, fields=None, exclude=None, if hasattr(form, 'Meta'): parent = (form.Meta, object) Meta = type(str('Meta'), parent, attrs) - + if formfield_callback: + Meta.formfield_callback = staticmethod(formfield_callback) # Give this new form class a reasonable name. class_name = model.__name__ + str('Form') diff --git a/tests/model_forms/tests.py b/tests/model_forms/tests.py index a2e7c66419..873699f921 100644 --- a/tests/model_forms/tests.py +++ b/tests/model_forms/tests.py @@ -2736,6 +2736,28 @@ class FormFieldCallbackTests(SimpleTestCase): with self.assertRaises(TypeError): modelform_factory(Person, fields="__all__", formfield_callback='not a function or callable') + def test_inherit_after_custom_callback(self): + def callback(db_field, **kwargs): + if isinstance(db_field, models.CharField): + return forms.CharField(widget=forms.Textarea) + return db_field.formfield(**kwargs) + + class BaseForm(forms.ModelForm): + class Meta: + model = Person + fields = '__all__' + + NewForm = modelform_factory(Person, form=BaseForm, formfield_callback=callback) + + class InheritedForm(NewForm): + pass + + for name in NewForm.base_fields.keys(): + self.assertEqual( + type(InheritedForm.base_fields[name].widget), + type(NewForm.base_fields[name].widget) + ) + class LocalizedModelFormTest(TestCase): def test_model_form_applies_localize_to_some_fields(self):