Last active
May 28, 2021 12:47
-
-
Save AndrewIngram/1724325685e681162fced2f672b5e6c2 to your computer and use it in GitHub Desktop.
Filter Count Mixin for Django's admin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib import admin | |
from django.db.models import Count, F | |
class FilterCountMixin(admin.SimpleListFilter): | |
def __init__(self, request, params, model, model_admin): | |
# Store the request so we can reapply all the filters properly later | |
self.request = request | |
super().__init__(request, params, model, model_admin) | |
def get_filter_counts_parameter_name(self): | |
return self.parameter_name | |
def get_filter_counts_queryset(self, qs): | |
return qs | |
def choices(self, changelist): | |
choices = super().choices(changelist) | |
qs = changelist.root_queryset | |
# To get the counts for *this* filter, we have to get the final queryset for the | |
# changelist with every filter applied *except* this one, then we can do our | |
# aggregations from that point. | |
for filter_spec in changelist.filter_specs: | |
if filter_spec is not self: | |
new_qs = filter_spec.queryset(self.request, qs) | |
if new_qs is not None: | |
qs = new_qs | |
counts = ( | |
self.get_filter_counts_queryset(qs) | |
.annotate(count_lookup_field=F(self.get_filter_counts_parameter_name())) | |
.values("count_lookup_field") | |
.annotate(total=Count("id")) | |
) | |
total = sum(x["total"] for x in counts) | |
lookup_choices = self.lookup_choices.copy() | |
lookup_choices.insert(0, None) | |
for (spec, choice) in zip(lookup_choices, choices): # type: ignore | |
if spec is None: | |
choice["display"] = f'{choice["display"]} ({total})' | |
else: | |
count = next( | |
(x["total"] for x in counts if x["count_lookup_field"] == spec[0]), | |
0, | |
) | |
choice["display"] = f'{choice["display"]} ({count})' | |
yield choice |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment