On my current project, I was faced with an interesting problem. My form includes a ChoiceField that is not required. However, the Django ChoiceField doesn’t allow for no choice. What was happening instead was a de facto default to the first option in the choice list unless the user picked another value – no way to select nothing.
A quick search turned up the EmptyChoiceField from Git user davidbgk – https://gist.github.com/davidbgk/651080, and it worked very well. In my form, I used the field type thusly:
suitability = EmptyChoiceField(required=False,empty_label=u"---------",choices=Suitability)
In David’s code, the empty label choice is prepended to the list when the field is not required and the empty_label parameter has a value. However, I wanted to see if I could make the EmptyChoiceField work more like the ModelChoiceField.
- The empty_label parameter defaults to
u"---------
- A required field has the empty field choice prepended to the list, unless an initial value is provided.
- When the field is not required, the empty field choice is always included, regardless of whether an initial value exists.
Here is my version of the field – https://gist.github.com/dashdrum/4960474:
from django.forms import ChoiceField
''' Based on https://gist.github.com/davidbgk/651080
modified to mirror the functionality of ModelChoiceField '''
class EmptyChoiceField(ChoiceField):
def __init__(self, choices=(), empty_label=u"---------", required=True, widget=None, label=None,
initial=None, help_text=None, *args, **kwargs):
# prepend an empty label unless the field is required AND
# an initial value is supplied
if required and (initial is not None):
pass # don't prepend the empty label
else:
choices = tuple([(u'', empty_label)] + list(choices))
super(EmptyChoiceField, self).__init__(choices=choices, required=required, widget=widget,
label=label, initial=initial, help_text=help_text,
*args, **kwargs)
My invocation of the field only changes in that I no longer need to specify a label text:
suitability = EmptyChoiceField(required=False,choices=Suitability)
By changing the default value of the empty_label, I have broken backward compatibility, although I have a tough time seeing a reason to use this field with the empty_label set to None on purpose. I’ll probably send a pull request back to the original author, but I will note that he may not want to merge it.
Hope this post helps someone else faced with a similar dilemma.