Default Boolean Filter in Django Admin
Asked Answered
P

3

7

I have seen the solution for a default choice field. Default filter in Django admin

It's not obvious how to extend that to a boolean field. I have an archive field that keeps things from being displayed. I'd like the default filter to be No instead of All.

Pyrrhuloxia answered 27/6, 2016 at 22:23 Comment(0)
M
8
class BooleanDefaultNoFilter(SimpleListFilter):
    def lookups(self, request, model_admin):
        return (
            ('all', 'All'),
            (1, 'Yes'),
            (None, 'No')
        )

    def choices(self, changelist):
        for lookup, title in self.lookup_choices:
            yield {
                'selected': self.value() == (str(lookup) if lookup else lookup),
                'query_string': changelist.get_query_string({self.parameter_name: lookup}, []),
                'display': title,
            }

    def queryset(self, request, queryset):
        if self.value():
            if self.value() == 'all':
                return queryset
            else:
                return queryset.filter(**{self.parameter_name: self.value()})

        elif self.value() == None:
            return queryset.filter(**{self.parameter_name: False})

class NamedFilter(BooleanDefaultNoFilter):
    title = _('InsertName')
    parameter_name = 'insertname'

class InsertNameAdmin(admin.ModelAdmin):
      list_filters = (NamedFilter)
Misogynist answered 6/3, 2020 at 20:0 Comment(2)
How to make it default to YES?Washing
Play around with (None, 'No') -> (None, 'Yes') I imagineMisogynist
M
1

I wanted the filter to show only Yes/No (without All), and to have Yes by default. That way I can avoid some of the confusion for the user to see the All option selected while actually having the Yes filter applied.

I came up with this:

class DefaultYesBooleanFieldListFilter(BooleanFieldListFilter):
    default = "1"

    def __init__(self, field, request, params, model, model_admin, field_path):
        super().__init__(field, request, params, model, model_admin, field_path)
        if not self.lookup_val:
            self.lookup_val = self.default
            self.used_parameters[self.lookup_kwarg] = self.default

    def choices(self, changelist):
        choices = super().choices(changelist)
        choices.__next__()
        for choice in choices:
            print(choice)
            yield choice


class DefaultNoBooleanFieldListFilter(DefaultYesBooleanFieldListFilter):
    default = "0"

Usage: the same as a normal BooleanFieldListFilter, that is,

class SomethingAdmin(admin.ModelAdmin):
    list_filter = (
        ("active", DefaultYesBooleanFieldListFilter),
    )

Note that users will still have the general link to show all results (or remove all filters) which will still cause some confusion.

I hope it's helpful for someone.

Magenta answered 18/8, 2022 at 15:5 Comment(2)
How to make the ALL value also displayed?Washing
I didn't try it, but looks like the most voted option by Andrew is doing thatMagenta
T
-1

Overriding the get_queryset method from django.contrib.admin.ModelAdmin is one way to solve this problem.

This method allows you to specify what object to return when requesting that resource from the admin site.

class MyModelAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super(MyModelAdmin, self).get_queryset(request)
        # Here's where we specify what to filter our queryset by.
        return qs.filter(archived=False) 
Torin answered 27/6, 2016 at 23:4 Comment(1)
This approach works well as a permanent filter. I have list_filter = ('archive') as well. I would like to be able to see the archived, I just don't want to see them by default. Is there a way to pass the filter information into get_queryset?Pyrrhuloxia

© 2022 - 2024 — McMap. All rights reserved.