Does using Django model choices for search filters add server load on every page request?
I’m building a Django-based classifieds website.
Previously, my search form populated districts and categories using database queries like:
districts = (
AdPost.objects
.filter(admin_verified=True)
.values_list("district", flat=True)
.distinct()
)
To improve consistency and performance, I’ve now moved both district and category to static choices in the model.
Example:
class AdPost(models.Model):
CATEGORY_CHOICES = [
('fish', 'fish'),
('cow', 'cow'),
]
DISTRICT_CHOICES = [
('e', 'e'),
('j', 'j'),
]
category = models.CharField(max_length=50, choices=CATEGORY_CHOICES)
district = models.CharField(max_length=30, choices=DISTRICT_CHOICES)
In my view, I now pass these directly:
categories = AdPost.CATEGORY_CHOICES
districts = AdPost.DISTRICT_CHOICES
And render them in the search form:
<select name="district">
{% for key, label in districts %}
<option value="{{ key }}">{{ label }}</option>
{% endfor %}
</select>
Question
Does using model choices like this add any noticeable server load on every page request, or are these choices loaded once and reused?
I want to confirm that this approach is safe and efficient compared to querying the database on each request.
What I expect (but want confirmation)
My understanding is that:
choices are static Python data
They are loaded once when Django starts
Rendering them in templates does not cause database queries
Is this correct?
Environment
Django 4.x
PostgreSQL / SQLite
Standard class-based views
Yes, choices defined on the model like this are static data inside Django, and do not incur a database lookup at any point. This makes them much more performant that your previous database lookup.
Yes, your understanding is absolutely correct.
Moving from database queries to static model choices is a standard optimization in Django. To answer your specific concerns:
Server Load: This approach adds zero database load on page requests.
Loading Mechanism: The
CHOICESlist is a standard Python class attribute. It is evaluated and loaded into memory once when the Python process (WSGI/ASGI) starts up.Rendering: Accessing
AdPost.CATEGORY_CHOICESin your view is simply reading a list from RAM. It is instant and does not touch the database.
Why this is a good move
Your previous query was actually quite expensive:
# This forces the DB to scan the table (or index), sort, and deduplicate strings.
# As the table grows, this query gets slower on every single page load.
districts = AdPost.objects.values_list("district", flat=True).distinct()
Your new approach removes that overhead entirely.
One Improvement for Django 4.x
Since you are on Django 4.x, I highly recommend using TextChoices instead of simple lists of tuples. It keeps your code cleaner, allows access to labels via the class, and provides better type safety.
Refactored models.py:
from django.db import models
from django.utils.translation import gettext_lazy as _
class AdPost(models.Model):
class Category(models.TextChoices):
FISH = 'fish', _('Fish')
COW = 'cow', _('Cow')
class District(models.TextChoices):
E_DISTRICT = 'e', _('District E')
J_DISTRICT = 'j', _('District J')
# Usage in field
category = models.CharField(max_length=50, choices=Category.choices)
district = models.CharField(max_length=30, choices=District.choices)
Refactored View:
# You can pass the class directly or just the .choices list
context['districts'] = AdPost.District.choices
The Trade-off
The only downside to static choices is maintainability, not performance.
Database (Old way): If you wanted to add a new district, you just add an Ad with that district. No code changes needed.
Static Choices (New way): To add a "Horse" category, you must edit the code and redeploy the application.
If your categories and districts rarely change (which is usually the case for "Districts"), static choices are the superior architectural choice.
That's all I think
This type of database querying and data retrieval from Django should NOT cause noticeable server load on every request, but this static data for it to be updated (for example if you added a new option; it is static data) it needs a page restart.