#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 [email protected].
To unsubscribe from this group, send email to
[email protected].
For more options, visit this group at
http://groups.google.com/group/django-updates?hl=en.