﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
27116	Deferrable Admin Filters	Austin Pua	nobody	"Hi Guys!

I implemented a custom `SimpleListFilter` for one of my projects, but due to the nature of what it does, it is a very expensive process. It involves, from a base queryset, splitting it into two copies and then performing additional filtering (different for each split), prefetching different objects per split, performing validation vs those prefetch objects, and then return `pk` values of all positive matches as a brand new queryset using `__in` lookup.

I read the django admin code, and due to the lazy evaluation of querysets, my custom `SimpleListFilter` ends up having to go through all entries of the model, even though there are other filters in place. Maybe my own code can use some optimizations, but is there any plausible use case for deferrable admin filters?

Basically, it should perform all other admin filtering first, so that the base queryset will be as small as possible which will limit the entries and also limit the number of `Prefetch()` objects. I was able to hack up some code (shown below) that does this, but is it sound to implement it out-of-the-box?

{{{
from django.contrib import admin
from django.contrib.admin.views.main import ChangeList

class MyTestFilter(admin.SimpleListFilter):
    # ...
    defer = True
    # ...

class MyTestChangeList(ChangeList):
    # ...

    def get_filters(self, request):
        filter_specs, status, lookup_params, use_distinct = super(MyTestChangeList, self).get_filters(request)
        revised_filter_specs = []
        deferred_filter_specs = []
        for filter_spec in filter_specs:
            if hasattr(filter_spec, 'defer') and filter_spec.defer:
                deferred_filter_specs.append(filter_spec)
            else:
                revised_filter_specs.append(filter_spec)
        self.deferred_filter_specs = deferred_filter_specs
        return revised_filter_specs, status, lookup_params, use_distinct

    def get_queryset(self, request):
        qs = super(MyTestChangeList, self).get_queryset(request)
        for filter_spec in self.deferred_filter_specs:
            new_qs = filter_spec.queryset(request, qs)
            if new_qs is not None:
                qs = new_qs
        return qs
}}}
"	New feature	closed	contrib.admin	dev	Normal	wontfix	admin SimpleListFilter		Unreviewed	0	0	0	0	0	0
