mirror of https://github.com/django/django.git
Fixed #20999 - Allow overriding formfield class with choices, without subclass restrictions.
Refs #18162. Thanks claudep and mjtamlyn for review.
This commit is contained in:
parent
b04f8ddbaa
commit
7211741fc5
|
@ -636,7 +636,7 @@ class Field(object):
|
||||||
def save_form_data(self, instance, data):
|
def save_form_data(self, instance, data):
|
||||||
setattr(instance, self.name, data)
|
setattr(instance, self.name, data)
|
||||||
|
|
||||||
def formfield(self, form_class=None, **kwargs):
|
def formfield(self, form_class=None, choices_form_class=None, **kwargs):
|
||||||
"""
|
"""
|
||||||
Returns a django.forms.Field instance for this database Field.
|
Returns a django.forms.Field instance for this database Field.
|
||||||
"""
|
"""
|
||||||
|
@ -657,7 +657,9 @@ class Field(object):
|
||||||
defaults['coerce'] = self.to_python
|
defaults['coerce'] = self.to_python
|
||||||
if self.null:
|
if self.null:
|
||||||
defaults['empty_value'] = None
|
defaults['empty_value'] = None
|
||||||
if form_class is None or not issubclass(form_class, forms.TypedChoiceField):
|
if choices_form_class is not None:
|
||||||
|
form_class = choices_form_class
|
||||||
|
else:
|
||||||
form_class = forms.TypedChoiceField
|
form_class = forms.TypedChoiceField
|
||||||
# Many of the subclass-specific formfield arguments (min_value,
|
# Many of the subclass-specific formfield arguments (min_value,
|
||||||
# max_value) don't apply for choice fields, so be sure to only pass
|
# max_value) don't apply for choice fields, so be sure to only pass
|
||||||
|
|
|
@ -617,17 +617,23 @@ prepared with :meth:`.get_prep_lookup`.
|
||||||
Specifying the form field for a model field
|
Specifying the form field for a model field
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
.. method:: Field.formfield(self, form_class=forms.CharField, **kwargs)
|
.. method:: Field.formfield(self, form_class=None, choices_form_class=None, **kwargs)
|
||||||
|
|
||||||
Returns the default form field to use when this field is displayed in a model.
|
Returns the default form field to use when this model field is displayed in a
|
||||||
This method is called by the :class:`~django.forms.ModelForm` helper.
|
form. This method is called by the :class:`~django.forms.ModelForm` helper.
|
||||||
|
|
||||||
|
The form field class can be specified via the ``form_class`` and
|
||||||
|
``choices_form_class`` arguments; the latter is used if the field has choices
|
||||||
|
specified, the former otherwise. If these arguments are not provided,
|
||||||
|
:class:`~django.forms.CharField` or :class:`~django.forms.TypedChoiceField`
|
||||||
|
will be used.
|
||||||
|
|
||||||
All of the ``kwargs`` dictionary is passed directly to the form field's
|
All of the ``kwargs`` dictionary is passed directly to the form field's
|
||||||
``__init__()`` method. Normally, all you need to do is set up a good default
|
``__init__()`` method. Normally, all you need to do is set up a good default
|
||||||
for the ``form_class`` argument and then delegate further handling to the
|
for the ``form_class`` (and maybe ``choices_form_class``) argument and then
|
||||||
parent class. This might require you to write a custom form field (and even a
|
delegate further handling to the parent class. This might require you to write
|
||||||
form widget). See the :doc:`forms documentation </topics/forms/index>` for
|
a custom form field (and even a form widget). See the :doc:`forms documentation
|
||||||
information about this.
|
</topics/forms/index>` for information about this.
|
||||||
|
|
||||||
Continuing our ongoing example, we can write the :meth:`.formfield` method as::
|
Continuing our ongoing example, we can write the :meth:`.formfield` method as::
|
||||||
|
|
||||||
|
|
|
@ -78,14 +78,12 @@ class BasicFieldTests(test.TestCase):
|
||||||
|
|
||||||
self.assertEqual(m._meta.get_field('id').verbose_name, 'verbose pk')
|
self.assertEqual(m._meta.get_field('id').verbose_name, 'verbose pk')
|
||||||
|
|
||||||
def test_formclass_with_choices(self):
|
def test_choices_form_class(self):
|
||||||
# regression for 18162
|
"""Can supply a custom choices form class. Regression for #20999."""
|
||||||
class CustomChoiceField(forms.TypedChoiceField):
|
choices = [('a', 'a')]
|
||||||
pass
|
|
||||||
choices = [('a@b.cc', 'a@b.cc'), ('b@b.cc', 'b@b.cc')]
|
|
||||||
field = models.CharField(choices=choices)
|
field = models.CharField(choices=choices)
|
||||||
klass = CustomChoiceField
|
klass = forms.TypedMultipleChoiceField
|
||||||
self.assertIsInstance(field.formfield(form_class=klass), klass)
|
self.assertIsInstance(field.formfield(choices_form_class=klass), klass)
|
||||||
|
|
||||||
|
|
||||||
class DecimalFieldTests(test.TestCase):
|
class DecimalFieldTests(test.TestCase):
|
||||||
|
|
Loading…
Reference in New Issue