Klaas van Schelven
Klaas van Schelven

Reputation: 2528

Django Forms: Show empty option that evaluates to None

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:

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

Answers (1)

Klaas van Schelven
Klaas van Schelven

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

Related Questions