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.