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
- 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.