Reputation: 2528
When using Django's ModelChoiceField
, with required=False, an extra choice ('', '--------')
is generated automatically. When selecting this option, it ends up as None
in the cleaned_data
. How do I (idiomatically) reproduce this behavior when using a regular ChoiceField
?
Some things I've noted:
('', '---------')
to the list of choices
, so it appears to be required to add it manually. I feel there should be a way to add it to the choices by setting one of the parameters differently, so if that exists I would love to hear it.''
to None
must still be done manually in the code that uses cleaned_data
. This means the code that deals with ModelChoiceField
s has to be subtly different from the ChoiceField
code, which may possibly lead to subtle bugs. Again: if someone knows better idioms, I'd love to hear that.TypedChoiceField
does some magic handling of ''
. In particular, it does not offer it to the coerce
function like one would expect.Consider the following code:
def int_or_none(s):
if s.isnumeric():
return int(s)
return None
class NoneForm(forms.Form):
field = forms.TypedChoiceField(
choices=[('', '--------'), ('1', 'One'), ('2', 'Two')],
required=False, coerce=int_or_none)
def home(request):
if request.method == "POST":
form = NoneForm(request.POST)
if form.is_valid():
assert type(form.cleaned_data['field']) in [int, type(None)]
print form.cleaned_data['field']
form = NoneForm()
return HttpResponse(
"""<form method="POST">""" +
form.as_table() +
"""<input type="submit"></form>""")
The assertion above fails!
Can it really be this hard to get Django's various versions of ChoiceField
to clean to None
in an idiomatic way?
Upvotes: 1
Views: 1122
Reputation: 2528
This is the result based on rantanplan's comment about the empty_value
parameter.
Note especially that the choice for the empty value is implemented as ''
in the choices (just like in ModelChoiceField
, so that's good).
class NoneForm(forms.Form):
field = forms.TypedChoiceField(
choices=[('', '--------'), ('1', 'One'), ('2', 'Two')],
required=False, coerce=int, empty_value=None)
def home(request):
if request.method == "POST":
form = NoneForm(request.POST)
if form.is_valid():
assert type(form.cleaned_data['field']) in [int, type(None)]
print form.cleaned_data['field']
form = NoneForm()
return HttpResponse(
"""<form method="POST">""" +
form.as_table() +
"""<input type="submit"></form>""")
Now the assertion succeeds.
Upvotes: 1