Loading django/db/models/fields/__init__.py +4 −2 Original line number Diff line number Diff line Loading @@ -636,7 +636,7 @@ class Field(object): def save_form_data(self, instance, 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. """ Loading @@ -657,7 +657,9 @@ class Field(object): defaults['coerce'] = self.to_python if self.null: 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 # Many of the subclass-specific formfield arguments (min_value, # max_value) don't apply for choice fields, so be sure to only pass Loading docs/howto/custom-model-fields.txt +13 −7 Original line number Diff line number Diff line Loading @@ -617,17 +617,23 @@ prepared with :meth:`.get_prep_lookup`. 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. This method is called by the :class:`~django.forms.ModelForm` helper. Returns the default form field to use when this model field is displayed in a 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 ``__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 parent class. This might require you to write a custom form field (and even a form widget). See the :doc:`forms documentation </topics/forms/index>` for information about this. for the ``form_class`` (and maybe ``choices_form_class``) argument and then delegate further handling to the parent class. This might require you to write a custom form field (and even a form widget). See the :doc:`forms documentation </topics/forms/index>` for information about this. Continuing our ongoing example, we can write the :meth:`.formfield` method as:: Loading tests/model_fields/tests.py +5 −7 Original line number Diff line number Diff line Loading @@ -78,14 +78,12 @@ class BasicFieldTests(test.TestCase): self.assertEqual(m._meta.get_field('id').verbose_name, 'verbose pk') def test_formclass_with_choices(self): # regression for 18162 class CustomChoiceField(forms.TypedChoiceField): pass choices = [('a@b.cc', 'a@b.cc'), ('b@b.cc', 'b@b.cc')] def test_choices_form_class(self): """Can supply a custom choices form class. Regression for #20999.""" choices = [('a', 'a')] field = models.CharField(choices=choices) klass = CustomChoiceField self.assertIsInstance(field.formfield(form_class=klass), klass) klass = forms.TypedMultipleChoiceField self.assertIsInstance(field.formfield(choices_form_class=klass), klass) class DecimalFieldTests(test.TestCase): Loading Loading
django/db/models/fields/__init__.py +4 −2 Original line number Diff line number Diff line Loading @@ -636,7 +636,7 @@ class Field(object): def save_form_data(self, instance, 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. """ Loading @@ -657,7 +657,9 @@ class Field(object): defaults['coerce'] = self.to_python if self.null: 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 # Many of the subclass-specific formfield arguments (min_value, # max_value) don't apply for choice fields, so be sure to only pass Loading
docs/howto/custom-model-fields.txt +13 −7 Original line number Diff line number Diff line Loading @@ -617,17 +617,23 @@ prepared with :meth:`.get_prep_lookup`. 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. This method is called by the :class:`~django.forms.ModelForm` helper. Returns the default form field to use when this model field is displayed in a 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 ``__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 parent class. This might require you to write a custom form field (and even a form widget). See the :doc:`forms documentation </topics/forms/index>` for information about this. for the ``form_class`` (and maybe ``choices_form_class``) argument and then delegate further handling to the parent class. This might require you to write a custom form field (and even a form widget). See the :doc:`forms documentation </topics/forms/index>` for information about this. Continuing our ongoing example, we can write the :meth:`.formfield` method as:: Loading
tests/model_fields/tests.py +5 −7 Original line number Diff line number Diff line Loading @@ -78,14 +78,12 @@ class BasicFieldTests(test.TestCase): self.assertEqual(m._meta.get_field('id').verbose_name, 'verbose pk') def test_formclass_with_choices(self): # regression for 18162 class CustomChoiceField(forms.TypedChoiceField): pass choices = [('a@b.cc', 'a@b.cc'), ('b@b.cc', 'b@b.cc')] def test_choices_form_class(self): """Can supply a custom choices form class. Regression for #20999.""" choices = [('a', 'a')] field = models.CharField(choices=choices) klass = CustomChoiceField self.assertIsInstance(field.formfield(form_class=klass), klass) klass = forms.TypedMultipleChoiceField self.assertIsInstance(field.formfield(choices_form_class=klass), klass) class DecimalFieldTests(test.TestCase): Loading