The Problem
Say you have a document with a status field. You define it like this in your model:
class Document(models.Model):
STATUS_CHOICES = [
('under_review', 'Under Review'),
('approved', 'Approved'),
('rejected', 'Rejected'),
]
status = models.CharField(max_length=20, choices=STATUS_CHOICES)
Django stores the left side (under_review) in the database. That's the raw value — short, clean, and easy to work with in code.
But when you display it in a template like this:
<p>Status: {{ document.status }}</p>
Your user sees:
Status: under_review
Not great. That's an internal value leaking out to the UI.
The Solution: get_<fieldname>_display()
Whenever you define choices on a field, Django automatically generates a method called get_<fieldname>_display() on your model. You don't write it — Django creates it for free.
It looks up the stored value and returns the human-readable label instead.
document.status # → 'under_review'
document.get_status_display() # → 'Under Review'
The naming rule is simple: get_ + your field name + _display. So if your field is called priority, the method is get_priority_display().
Using It in Templates
In Django templates, you call methods without parentheses:
<!-- Raw value — not ideal -->
<p>Status: {{ document.status }}</p>
<!-- Human-readable label — much better -->
<p>Status: {{ document.get_status_display }}</p>
The second line now shows:
Status: Under Review
This Is Not About Dropdowns
A common point of confusion: this method has nothing to do with rendering a <select> dropdown. That's the form's job.
When you use a choices field in a Django form, the form automatically renders a dropdown for input. That's separate.
get_status_display() is only for reading and displaying already-saved data — like in a document list page or a detail view.
| What you want | How Django handles it |
|---|---|
| Show a dropdown for input | Django form renders <select> automatically |
| Display the saved value nicely | Use get_status_display in your template |
A Real Example
Here's how this fits together end to end:
models.py
class Document(models.Model):
STATUS_CHOICES = [
('under_review', 'Under Review'),
('approved', 'Approved'),
('rejected', 'Rejected'),
]
title = models.CharField(max_length=200)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='under_review')
document_list.html
{% for document in documents %}
<tr>
<td>{{ document.title }}</td>
<td>{{ document.get_status_display }}</td> <!-- Shows "Under Review", not "under_review" -->
</tr>
{% endfor %}
Clean, readable, and no extra code needed.
Summary
- Django stores the raw value (left side of the tuple) in the database
- The label (right side) is for humans
- Django auto-generates
get_<fieldname>_display()for any field withchoices - Use it in templates as
{{ object.get_fieldname_display }}(no parentheses) - It's for displaying data, not for rendering forms or dropdowns
Next time you define choices on a field, you get this for free. One less thing to build yourself.