82

I have a ChoiceField, now how do I get the label when I need it?

class ContactForm(forms.Form):
     reason = forms.ChoiceField(choices=[("feature", "A feature"),
                                         ("order", "An order")],
                                widget=forms.RadioSelect)

form.cleaned_data["reason"] only gives me the feature or order values or so.

Advena
  • 1,664
  • 2
  • 24
  • 45
webjunkie
  • 6,891
  • 7
  • 46
  • 43
  • 1
    I think you may need to reconsider which answer is the accepted one.. – Dan Abramov Sep 18 '11 at 22:36
  • @Dan: Why? Which one do you prefer? – webjunkie Sep 26 '11 at 15:40
  • @webjunkie The one with the most up-votes is the more django-centric one which requires less code be written on a per-model basis. – Jack M. Jul 24 '12 at 16:50
  • 1
    @JackM. if you mean @shacker's, it doesn't actually answer the question. `get_FOO_display` applies to `django.db.models.ChoiceField`, not `django.forms.ChoiceField`. The currently-accepted answer (by Andrés) is the best one can do as of Django 1.5, I believe. – supervacuo Feb 15 '13 at 19:02
  • The accepted answer also works in more cases. For example if you query the `FOO` table, but want a `dict` rather than a model (using `FOO.objects.values()`), it will work with tiny adjustments. @shacker's answer works only for full-fledged models. – Eduard Luca Jul 07 '14 at 14:23
  • Weird enough, Django considers in this example `feature` and `order` as values, and `A feature`, `An order` as labels. [Source](https://docs.djangoproject.com/en/4.0/ref/models/fields/#enumeration-types) – Advena Feb 13 '22 at 09:22

10 Answers10

168

See the docs on Model.get_FOO_display(). So, should be something like :

ContactForm.get_reason_display()

In a template, use like this:

{{ OBJNAME.get_FIELDNAME_display }}
shacker
  • 14,712
  • 8
  • 89
  • 89
98

This may help:

reason = form.cleaned_data['reason']
reason = dict(form.fields['reason'].choices)[reason]
  • 2
    Django [allows grouped choices](https://docs.djangoproject.com/en/2.0/ref/models/fields/#choices). If you have those, this won't work. – mlissner Mar 28 '18 at 20:34
29

This the easiest way to do this: Model instance reference: Model.get_FOO_display()

You can use this function which will return the display name: ObjectName.get_FieldName_display()

Replace ObjectName with your class name and FieldName with the field of which you need to fetch the display name of.

deadly
  • 1,194
  • 14
  • 24
Kumar
  • 407
  • 4
  • 6
9

If the form instance is bound, you can use

chosen_label = form.instance.get_FOO_display()
krubo
  • 5,969
  • 4
  • 37
  • 46
4

Here is a way I came up with. There may be an easier way. I tested it using python manage.py shell:

>>> cf = ContactForm({'reason': 'feature'})
>>> cf.is_valid()
True
>>> cf.fields['reason'].choices
[('feature', 'A feature')]
>>> for val in cf.fields['reason'].choices:
...     if val[0] == cf.cleaned_data['reason']:
...             print val[1]
...             break
...
A feature

Note: This probably isn't very Pythonic, but it demonstrates where the data you need can be found.

Ryan Duffield
  • 18,497
  • 6
  • 40
  • 40
  • 1
    Is there any word on if this sort of thing is part of core now? It's unfathomable that this isn't in the form API yet I have a hard time googling for a better solution. – M. Ryan Apr 08 '11 at 04:37
3

You can have your form like this:

#forms.py
CHOICES = [('feature', "A feature"), ("order", "An order")]
class ContactForm(forms.Form):
     reason = forms.ChoiceField(choices=CHOICES,
                                widget=forms.RadioSelect)

Then this would give you what you want:

reason = dict(CHOICES)[form.cleaned_data["reason"]]
mousetail
  • 7,009
  • 4
  • 25
  • 45
Akshar Raaj
  • 14,231
  • 7
  • 51
  • 45
2

OK. I know this is very old post, but reading it helped me a lot. And I think I have something to add.

The crux of the matter here is that the the model method.

ObjectName.get_FieldName_display()

does not work for forms.

If you have a form, that is not based on a model and that form has a choice field, how do you get the display value of a given choice.

Here is some code that might help you.

You can use this code to get the display value of a choice field from a posted form.

display_of_choice = dict(dateform.fields['fieldnane'].choices)[int(request.POST.get('fieldname'))]

the 'int' is there on the basis the choice selection was a integer. If the choice index was a string then you just remove the int(...)

Paul West
  • 81
  • 8
  • Any idea how to display the display value of a given choice in a template? I.E. Doesn't seem like `{{form.get_fieldchoice_display}}` works – nick_rinaldi Nov 10 '21 at 19:14
  • There is my answer above, plus there are number of valid answers in subsequent posts. All give options at you disposal, if you want a specific answer, then post your actual code and we can give you specific answer, happy to do so. – Paul West Nov 11 '21 at 23:02
1

Im using @Andrés Torres Marroquín way, and I want share my implementation.

GOOD_CATEGORY_CHOICES = (
    ('paper', 'this is paper'),
    ('glass', 'this is glass'),
    ...
)

class Good(models.Model):
    ...
    good_category = models.CharField(max_length=255, null=True, blank=False)
    ....

class GoodForm(ModelForm):
    class Meta:
        model = Good
        ...

    good_category = forms.ChoiceField(required=True, choices=GOOD_CATEGORY_CHOICES)
    ...


    def clean_good_category(self):
        value = self.cleaned_data.get('good_category')

        return dict(self.fields['good_category'].choices)[value]

And the result is this is paper instead of paper. Hope this help

Ardi Nusawan
  • 427
  • 6
  • 12
1

confirm that Ardi's and Paul's response are best for forms and not models. Generalizing Ardi's to any parameter:

    class AnyForm(forms.Form):
        def get_field_name_display(self, field_name):
            return dict(self.fields[field_name].choices[self.cleaned_data[field_name]]

Or put this method in a separate class, and sub-class it in your form

class ChoiceFieldDisplayMixin:
    def get_field_name_display(self, field_name):
        return dict(self.fields[field_name].choices[self.cleaned_data[field_name]]


class AnyCustomForm(forms.Form, ChoiceFieldDisplayMixin):
    choice_field_form = forms.ChoiceField(choices=[...])

Now call the same method for any Choice Field:

form_instance = AnyCustomForm()
form_instance.is_valid()
form_instance.get_field_name_display('choice_field_form')
Mark D
  • 11
  • 2
  • now mix it up with a metaclass, and you'll end up with the get_FOO_display thing you can easily use in templates, as you'd do with models...isn't this what everybody wants? – benzkji Mar 24 '23 at 09:50
0

I think maybe @webjunkie is right.

If you're reading from the form from a POST then you would do

def contact_view(request):
    if request.method == 'POST':
        form = ContactForm(request.POST)
        if form.is_valid():
            contact = form.save()
            contact.reason = form.cleaned_data['reason']
            contact.save()
Noel Evans
  • 8,113
  • 8
  • 48
  • 58