Django admin: Filter field by range

Question:

I have a model called Person. Person has fields like name/surname and age. Now what I want to achieve is to have a filter in django admin that can filter age in some custom ranges so 10-15.

After reading some posts my best shoot is:

class RangeFilter(SimpleListFilter):
    title = 'Age filter'
    parameter_name = 'age'
    
    def lookups(self, request, model_admin):
        
        return [
            (1, '0-5'),
            (2, '5-10'),
            (3, '10-15'),
            (4, '15-20')]

    def queryset(self, request, queryset):
        filt_age = request.GET.get('age')
        return queryset.filter(
                    age__range=self.age_dict[filt_age]
                )

But this yields an error
‘RangeFilter’ object has no attribute ‘age_dict’.

Asked By: rafaelHTML

||

Answers:

probably you mean:

def lookups(self, request, model_admin):    
    return ('1', '0-5'),('2', '5-10'), ('3', '10-15'), ('4', '15-20')

def queryset(self, request, queryset):
    filt_age = request.GET.get('age')
    age_dict = dict(self.lookups(None, None))
    if age_dict.get(filt_age):
        return queryset.filter(age__range=age_dict[filt_age])
    return queryset

return queryset.filter(age__range=dict(self.lookups(None, None))[filt_age])
Answered By: Maxim Danilov

It’s a bit hard to guess what are you trying to do, my attempt would be:

class RangeFilter(SimpleListFilter):
    title = 'Age filter'
    parameter_name = 'age'

    age_dict = {
        1: (0, 5),
        2: (5, 10),
        3: (10, 15),
        4: (15, 20)
    }

    def lookups(self, request, model_admin):
        return [(k, '-'.join(map(str, v))) for k, v in self.age_dict.items()]

    def queryset(self, request, queryset):
        filt_age = request.GET.get('age')
        return queryset.filter(
            age__range=self.age_dict[filt_age]
        )
Answered By: funnydman

I don’t know what you are trying to do but I give you the example below to filter persons by age following the documentation:

# "store/models.py"

from django.db import models

class Person(models.Model):
    name = models.CharField(max_length=20)
    age =  models.IntegerField()

    def __str__(self):
        return self.name
# "store/admin.py"

from django.contrib import admin
from .models import Person

class PersonAgeFilter(admin.SimpleListFilter):
    title = 'Person Age Filter'
    parameter_name = 'age'

    def lookups(self, request, model_admin):
        return (
            ("0-19", '0-19 years'),
            ("20-39", '20-39 years'),
            ("40-59", '40-59 years'),
            ("60<=", '60 years and over'),
        )

    def queryset(self, request, queryset):
        if self.value() == '0-19':
            return queryset.filter(age__lte=19)
        if self.value() == '20-39':
            return queryset.filter(age__range=(20, 39))
        if self.value() == '40-59':
            return queryset.filter(age__range=(40, 59))
        if self.value() == '60<=':
            return queryset.filter(age__gte=60)

@admin.register(Person)
class PersonAdmin(admin.ModelAdmin):
    list_display = ('name', 'age')
    list_filter = (PersonAgeFilter,)

Then, the filter section appears and there are 6 persons as shown below:

enter image description here

Then, when clicking on 20-39 year, 6 persons are filtered to 3 persons as shown below:

enter image description here

Answered By: Kai – Kazuya Ito