#27116: Deferrable Admin Filters
-------------------------------+------------------------------------
     Reporter:  malefice       |      Owner:  nobody
         Type:  New feature    |     Status:  new
    Component:  contrib.admin  |    Version:  master
     Severity:  Normal         |   Keywords:  admin SimpleListFilter
 Triage Stage:  Unreviewed     |  Has patch:  0
Easy pickings:  0              |      UI/UX:  0
-------------------------------+------------------------------------
 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
 }}}

--
Ticket URL: <https://code.djangoproject.com/ticket/27116>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/051.a67d5a835eacbd81058869193ea71a93%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to