Ticket #13095: 13095-formfield_callback-r13517.diff

File 13095-formfield_callback-r13517.diff, 7.5 KB (added by vung, 14 years ago)

Use None as default value for formfield_callback (patch from #13633+tests)

  • django/forms/models.py

     
    150150            data[f.name] = f.value_from_object(instance)
    151151    return data
    152152
    153 def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_callback=lambda f, **kwargs: f.formfield(**kwargs)):
     153def fields_for_model(model, fields=None, exclude=None, widgets=None, formfield_callback=None):
    154154    """
    155155    Returns a ``SortedDict`` containing form fields for the given model.
    156156
     
    175175            kwargs = {'widget': widgets[f.name]}
    176176        else:
    177177            kwargs = {}
    178         formfield = formfield_callback(f, **kwargs)
     178
     179        if formfield_callback is None:
     180            formfield = f.formfield(**kwargs)
     181        else:
     182            formfield = formfield_callback(f, **kwargs)
     183
    179184        if formfield:
    180185            field_list.append((f.name, formfield))
    181186        else:
     
    198203
    199204class ModelFormMetaclass(type):
    200205    def __new__(cls, name, bases, attrs):
    201         formfield_callback = attrs.pop('formfield_callback',
    202                 lambda f, **kwargs: f.formfield(**kwargs))
     206        formfield_callback = attrs.pop('formfield_callback', None)
    203207        try:
    204208            parents = [b for b in bases if issubclass(b, ModelForm)]
    205209        except NameError:
     
    376380    __metaclass__ = ModelFormMetaclass
    377381
    378382def modelform_factory(model, form=ModelForm, fields=None, exclude=None,
    379                        formfield_callback=lambda f: f.formfield()):
     383                       formfield_callback=None):
    380384    # Create the inner Meta class. FIXME: ideally, we should be able to
    381385    # construct a ModelForm without creating and passing in a temporary
    382386    # inner class.
     
    658662            form.fields[self._pk_field.name] = ModelChoiceField(qs, initial=pk_value, required=False, widget=HiddenInput)
    659663        super(BaseModelFormSet, self).add_fields(form, index)
    660664
    661 def modelformset_factory(model, form=ModelForm, formfield_callback=lambda f: f.formfield(),
     665def modelformset_factory(model, form=ModelForm, formfield_callback=None,
    662666                         formset=BaseModelFormSet,
    663667                         extra=1, can_delete=False, can_order=False,
    664668                         max_num=None, fields=None, exclude=None):
     
    813817                          formset=BaseInlineFormSet, fk_name=None,
    814818                          fields=None, exclude=None,
    815819                          extra=3, can_order=False, can_delete=True, max_num=None,
    816                           formfield_callback=lambda f: f.formfield()):
     820                          formfield_callback=None):
    817821    """
    818822    Returns an ``InlineFormSet`` for the given kwargs.
    819823
  • tests/regressiontests/model_forms_regress/tests.py

     
    250250        form.is_valid()
    251251        # self.assertTrue(form.is_valid())
    252252        # self.assertEquals(form.cleaned_data['url'], 'http://example.com/test')
     253
     254
     255class FormFieldCallbackTests(TestCase):
     256
     257    def test_baseform_with_widgets_in_meta(self):
     258        """
     259        Regression for #13095: Using base forms with widgets
     260        defined in Meta should not raise errors.
     261        """
     262        widget = forms.Textarea()
     263
     264        class BaseForm(forms.ModelForm):
     265            class Meta:
     266                model = Person
     267                widgets = {'name': widget}
     268
     269        Form = modelform_factory(Person, form=BaseForm)
     270        self.assertTrue(Form.base_fields['name'].widget is widget)
     271
     272    def test_custom_callback(self):
     273        """Test that a custom formfield_callback is used if provided"""
     274
     275        callback_args = []
     276
     277        def callback(db_field, **kwargs):
     278            callback_args.append((db_field, kwargs))
     279            return db_field.formfield(**kwargs)
     280
     281        widget = forms.Textarea()
     282
     283        class BaseForm(forms.ModelForm):
     284            class Meta:
     285                model = Person
     286                widgets = {'name': widget}
     287
     288        _ = modelform_factory(Person, form=BaseForm,
     289                              formfield_callback=callback)
     290        id_field, name_field = Person._meta.fields
     291
     292        self.assertEqual(callback_args,
     293                         [(id_field, {}), (name_field, {'widget': widget})])
     294
     295    def test_bad_callback(self):
     296        # A bad callback provided by user still gives an error
     297        self.assertRaises(TypeError, modelform_factory, Person,
     298                          widgets={'name': forms.Textarea()},
     299                          formfield_callback=lambda f: f.formfield())
  • tests/regressiontests/model_formsets_regress/tests.py

     
    1 from django.forms.models import modelform_factory, inlineformset_factory
     1from django import forms
     2from django.forms.models import modelform_factory, inlineformset_factory, modelformset_factory
    23from django.test import TestCase
    34
    45from models import User, UserSite, Restaurant, Manager
    56
     7
    68class InlineFormsetTests(TestCase):
    79    def test_formset_over_to_field(self):
    810        "A formset over a ForeignKey with a to_field can be saved. Regression for #10243"
     
    156158        # you can create a formset with an instance of None
    157159        form = Form(instance=None)
    158160        formset = FormSet(instance=None)
     161
     162
     163class CustomWidget(forms.CharField):
     164    pass
     165
     166
     167class UserSiteForm(forms.ModelForm):
     168    class Meta:
     169        model = UserSite
     170        widgets = {'data': CustomWidget}
     171
     172
     173class Callback(object):
     174
     175    def __init__(self):
     176        self.log = []
     177
     178    def __call__(self, db_field, **kwargs):
     179        self.log.append((db_field, kwargs))
     180        return db_field.formfield(**kwargs)
     181
     182
     183class FormfieldCallbackTests(TestCase):
     184    """
     185    Regression for #13095: Using base forms with widgets
     186    defined in Meta should not raise errors.
     187    """
     188
     189    def test_inlineformset_factory_default(self):
     190        Formset = inlineformset_factory(User, UserSite, form=UserSiteForm)
     191        form = Formset({}).forms[0]
     192        self.assertTrue(isinstance(form['data'].field.widget, CustomWidget))
     193
     194    def test_modelformset_factory_default(self):
     195        Formset = modelformset_factory(UserSite, form=UserSiteForm)
     196        form = Formset({}).forms[0]
     197        self.assertTrue(isinstance(form['data'].field.widget, CustomWidget))
     198
     199    def assertCallbackCalled(self, callback):
     200        id_field, user_field, data_field = UserSite._meta.fields
     201        expected_log = [
     202            (id_field, {}),
     203            (user_field, {}),
     204            (data_field, {'widget': CustomWidget}),
     205        ]
     206        self.assertEqual(callback.log, expected_log)
     207
     208    def test_inlineformset_custom_callback(self):
     209        callback = Callback()
     210        inlineformset_factory(User, UserSite, form=UserSiteForm,
     211                              formfield_callback=callback)
     212        self.assertCallbackCalled(callback)
     213
     214    def test_modelformset_custom_callback(self):
     215        callback = Callback()
     216        modelformset_factory(UserSite, form=UserSiteForm,
     217                             formfield_callback=callback)
     218        self.assertCallbackCalled(callback)
Back to Top