Skip to content

Instantly share code, notes, and snippets.

@rseabrook
Created October 8, 2021 18:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rseabrook/58c5ea2a70d07dd057116d180d417d18 to your computer and use it in GitHub Desktop.
Save rseabrook/58c5ea2a70d07dd057116d180d417d18 to your computer and use it in GitHub Desktop.
Django - create an admin list filter on a calculated value
from django.contrib import admin
from .filters import CalculatedFieldFilter
from .models import Item
@admin.register(Item)
class ItemAdmin(admin.ModelAdmin):
list_display = ('val', 'calculated_field')
list_filter = (CalculatedFieldFilter, )

Create an admin list filter on a calculated value

What

Filter a list in the Django admin based on a calculated field

Why

The Django admin list_filter option only accepts model field names. You cannot filter based on a model method or callable, although you can display the value of a model method in the list_display option. If you want to filter by a calculated value, you will need to use a custom filter that queries the database for the objects you want.

Why Not

You may be better off creating a non-editable database field, overriding the save() method to populate that field, and then using that field in the default list_filter.

How

Create a custom Django admin list filter that implements the logic of your calculated field

  • Create your model
  • Define a custom list filter that queries the database according to whatever logic you need
  • Add your custom filter to the list_filter option of your admin class
from django.contrib import admin
from django.db import models
class CalculatedFieldFilter(admin.SimpleListFilter):
title = 'calculated value' # this is shown in the admin as the filter heading. Ex. "By calculated value"
parameter_name = 'calculated_value' # this is the parameter used in the admin URL along with the lookups below. Ex. calculated_value=1
def lookups(self, request, model_admin):
# these are two-tuples of (parameter_value, human-readable_option_name)
return (
(1, 'The answer'),
(0, 'Not the answer'),
)
def queryset(self, request, queryset):
# this mirrors the logic in our models calculated_field method, but performs the operation in the database instead of in python
lookup_condition = models.Q(val=42)
if self.value() == 1:
return queryset.filter(lookup_condition)
if self.value() == 0:
return queryset.exclude(lookup_condition)
from django.db import models
class Item(models.Model):
val = models.IntField()
def calculated_field(self):
if self.val == 42:
return 'The answer'
else:
return 'Not the answer'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment