#9245: Using choices in a mode field forces use of TypedChoiceField in a form
field
------------------------+------------------------------------
     Reporter:  Tarken  |                    Owner:  badri
         Type:  Bug     |                   Status:  reopened
    Component:  Forms   |                  Version:  1.0
     Severity:  Normal  |               Resolution:
     Keywords:          |             Triage Stage:  Accepted
    Has patch:  1       |      Needs documentation:  1
  Needs tests:  0       |  Patch needs improvement:  0
Easy pickings:  0       |                    UI/UX:  0
------------------------+------------------------------------
Changes (by dgouldin):

 * cc: dgouldin (added)


Comment:

 Julien, this patch will not work as-is. Your new Field.choices_formfield
 function is called from Field.formfield using **defaults, but defaults
 will never include form_class. This means that Field.choices_formfield
 will always be called with its default value for form_class (None unless
 overridden by a custom Field subclass) even when the user's intent was to
 provide a custom form_class for that model field. So for this model:

 {{{
 class Foo(models.Model):
     bar = models.IntegerField(choices=bar_choices,
 form_class=MyCustomFormClass)
 }}}

 MyCustomFormClass would never make it to bar's Field.choices_formfield,
 and so an instance of it would not be returned by Field.formfield.

 However, it also not work to simply call
 self.choices_formfield(form_class=form_class, **defaults) from
 Field.formfield. Subclasses of Field (such as IntegerField) frequently
 override formfield() and call super's formfield() with a form_class kwarg.
 This means that calling Field.choices_formfield with Field.formfield's
 form_class would break models like this:


 {{{
 class Foo(models.Model):
     bar = models.IntegerField(choices=bar_choices)
 }}}

 In this case, IntegerField.formfield would call Field.formfield with
 form_class=forms.IntegerField, which would then be passed through to
 Field.choices_formfield, causing forms.TypedChoiceField not to be used as
 was intended.

 As the implementation sits currently, Field has no way to determine
 whether the intent of the user was to specify their own form_class or
 whether the Field subclass injected its own form_class before calling
 Field.formfield. This is broken, plain and simple. In order for
 Field.formfield to make a good decision about which class to use when
 instantiating a form field, it needs both pieces of information: the model
 field's default form_class, and the user's override of that default (if
 provided). Here's the solution I propose:

 {{{
 class Field(object):
     default_form_class = forms.CharField

     # ...

     def formfield(self, form_class=None, **kwargs):
         if self.choices:
             form_class = form_class or forms.TypedChoiceField
             # ...
         else:
             form_class = form_class or self.default_form_class


 class IntegerField(Field):
     default_form_class = forms.IntegerField
 }}}

 This allows Field.formfield to have both pieces of information, and it
 alleviates the need for IntegerField to override formfield. It is not
 backwards compatible, as any model field subclasses which use this
 formfield override approach would need to be changed to fit the new
 default_form_class property approach.

-- 
Ticket URL: <https://code.djangoproject.com/ticket/9245#comment:15>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To post to this group, send email to django-updates@googlegroups.com.
To unsubscribe from this group, send email to 
django-updates+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/django-updates?hl=en.

Reply via email to