Django
ChoiceField
Web Development
Python
Forms

Django Display Choice Value

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Django model choices solve a common problem: storing compact values in the database while showing friendly labels to users. The pattern is simple, but many projects still display raw codes in templates, APIs, or admin views. This article shows how to display choice labels cleanly across models, forms, templates, and serializers.

Define Choices Clearly in the Model

A choice field stores the machine value and maps it to a human-readable label. Modern Django code should prefer TextChoices for readability and safer references.

python
1from django.db import models
2
3
4class Order(models.Model):
5    class Status(models.TextChoices):
6        PENDING = "P", "Pending"
7        PAID = "D", "Paid"
8        CANCELED = "C", "Canceled"
9
10    number = models.CharField(max_length=20)
11    status = models.CharField(
12        max_length=1,
13        choices=Status.choices,
14        default=Status.PENDING,
15    )

This gives you a compact value in the database and a stable place to reference valid states in code.

Use get_FIELD_display for Human Labels

Django automatically adds a method named get_<field>_display for fields that define choices. This is the most direct way to show labels.

python
order = Order(number="A-100", status=Order.Status.PAID)
print(order.status)                # D
print(order.get_status_display())  # Paid

In templates, call the method without parentheses.

django
<p>Order: {{ order.number }}</p>
<p>Status: {{ order.get_status_display }}</p>

That small change prevents UI bugs where users see one-letter state codes.

Use Choice Labels in Forms and Admin

Django forms and admin usually render labels automatically when the field has choices. You can still customize behavior to keep labels consistent.

python
1from django import forms
2from .models import Order
3
4
5class OrderForm(forms.ModelForm):
6    class Meta:
7        model = Order
8        fields = ["number", "status"]

When this form renders status, users see Pending, Paid, and Canceled, not P, D, or C. In admin list views, add a helper to show labels explicitly.

python
1from django.contrib import admin
2from .models import Order
3
4
5@admin.register(Order)
6class OrderAdmin(admin.ModelAdmin):
7    list_display = ["number", "status_label"]
8
9    @admin.display(description="Status")
10    def status_label(self, obj):
11        return obj.get_status_display()

API Serialization Patterns

If you expose data through an API, decide whether clients should receive values, labels, or both. Returning both is often safest.

python
1from rest_framework import serializers
2from .models import Order
3
4
5class OrderSerializer(serializers.ModelSerializer):
6    status_label = serializers.CharField(source="get_status_display", read_only=True)
7
8    class Meta:
9        model = Order
10        fields = ["number", "status", "status_label"]

This keeps backend logic compact while giving frontend code exactly what it needs.

Internationalization and Consistent Labels

If your app supports multiple languages, keep labels translatable at the model layer. Django can localize choice labels cleanly when you wrap them with lazy translation. This ensures templates, forms, and admin all use the same translated text.

python
1from django.db import models
2from django.utils.translation import gettext_lazy as _
3
4
5class Ticket(models.Model):
6    class Priority(models.TextChoices):
7        LOW = "L", _("Low")
8        MEDIUM = "M", _("Medium")
9        HIGH = "H", _("High")
10
11    priority = models.CharField(max_length=1, choices=Priority.choices)

Remember that filtering still uses stored values, not translated labels.

python
high_priority = Ticket.objects.filter(priority=Ticket.Priority.HIGH)

This split is intentional: database values remain stable while labels adapt to user locale.

Common Pitfalls

The most common mistake is hardcoding labels in templates with manual if statements. That duplicates logic and drifts from model definitions. Another issue is storing label text directly in the database instead of stable short codes, which makes localization and migration harder. Teams also sometimes mix old tuple based choices and enum based choices in the same model area, making the code harder to navigate. Finally, API payloads often ship only the compact value, then frontend teams reimplement a mapping table. Return a label field when client readability matters.

Summary

  • Use TextChoices to define choice values and labels in one place.
  • Display labels with get_FIELD_display in Python code and templates.
  • Let forms and admin render labels from model choices.
  • For APIs, consider returning both stored value and display label.
  • Avoid duplicated mapping logic across templates and frontend clients.

Course illustration
Course illustration

All Rights Reserved.