Filter default di admin Django

94

Bagaimana cara mengubah pilihan filter default dari 'ALL'? Saya memiliki lapangan bernama statusyang memiliki tiga nilai: activate, pendingdan rejected. Ketika saya menggunakan list_filterdalam admin Django, filter secara default disetel ke 'Semua' tetapi saya ingin menyetelnya ke tertunda secara default.

ha22109
sumber

Jawaban:

102

Untuk mencapai hal ini dan memiliki link 'Semua' yang dapat digunakan di sidebar Anda (yaitu yang menampilkan semua daripada menampilkan menunggu), Anda perlu membuat filter daftar kustom, mewarisi dari django.contrib.admin.filters.SimpleListFilterdan memfilter 'tertunda' secara default. Sesuatu seperti ini seharusnya bekerja:

from datetime import date

from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter

class StatusFilter(SimpleListFilter):
    title = _('Status')

    parameter_name = 'status'

    def lookups(self, request, model_admin):
        return (
            (None, _('Pending')),
            ('activate', _('Activate')),
            ('rejected', _('Rejected')),
            ('all', _('All')),
        )

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

    def queryset(self, request, queryset):
        if self.value() in ('activate', 'rejected'):
            return queryset.filter(status=self.value())    
        elif self.value() == None:
            return queryset.filter(status='pending')


class Admin(admin.ModelAdmin): 
    list_filter = [StatusFilter] 

EDIT: Membutuhkan Django 1.4 (terima kasih Simon)

Greg
sumber
3
Ini adalah solusi terbersih dari semuanya, namun memiliki upvote paling sedikit ... ini membutuhkan Django 1.4, meskipun, itu seharusnya sudah diberikan sekarang.
Simon
@Greg Bagaimana Anda benar-benar menghapus fungsionalitas filter dan tab filter dari halaman admin?
2
Solusi ini memiliki kelemahan kecil. Ketika filter kosong (sebenarnya menggunakan filter 'tertunda'), Django 1.8 salah menentukan jumlah hasil lengkap dan tidak menampilkan hitungan hasil jika show_full_result_count adalah True (secara default). -
Alexander Fedotov
Perhatikan bahwa jika Anda gagal menimpa choicesmetode dalam solusi, itu akan terus menambahkan opsi Semua miliknya sendiri di bagian atas daftar pilihan.
richard
47
class MyModelAdmin(admin.ModelAdmin):   

    def changelist_view(self, request, extra_context=None):

        if not request.GET.has_key('decommissioned__exact'):

            q = request.GET.copy()
            q['decommissioned__exact'] = 'N'
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
ha22109
sumber
18
Solusi ini memiliki kelemahan yaitu meskipun pilihan "Semua" masih ditampilkan di UI, memilihnya tetap menerapkan pemfilteran default.
akaihola
saya memiliki pertanyaan yang sama, tetapi saya dapat memahami tayangan ulangnya
Asinox
Ini bagus tetapi saya perlu melihat parameter get di url sehingga filter saya dapat mengambilnya dan menampilkannya dipilih. Memposting solusi saya segera.
radtek
penjelasan hilang. hanya memposting sepotong kode mungkin tidak membantu semua orang. di atas itu tidak berfungsi dan tanpa sedikit konteks sulit untuk mencari tahu mengapa
EvilSmurf
19

Mengambil jawaban ha22109 di atas dan dimodifikasi untuk memungkinkan pemilihan "Semua" dengan membandingkan HTTP_REFERERdan PATH_INFO.

class MyModelAdmin(admin.ModelAdmin):

    def changelist_view(self, request, extra_context=None):

        test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO'])

        if test[-1] and not test[-1].startswith('?'):
            if not request.GET.has_key('decommissioned__exact'):

                q = request.GET.copy()
                q['decommissioned__exact'] = 'N'
                request.GET = q
                request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)
warnawarni
sumber
3
Ini mengganggu saya karena HTTP_REFERER tidak selalu ada. Saya melakukan 'referer = request.META.get (' HTTP_REFERER ',' '); test = referer.split (request.META ['PATH_INFO']) `
penulis ben
@Ben Saya menggunakan dua baris referer = request.META.get ('HTTP_REFERER', '') test = referer.split (request.META ['PATH_INFO']). Saya tidak banyak tentang HTTP_REFERER. Apakah masalah telah diperbaiki sepenuhnya dari baris ini jika HTTP_REFERER tidak ada.
the_game
@ the_game ya, idenya adalah jika Anda menggunakan tanda kurung siku untuk mencoba mengakses kunci yang tidak ada, itu melempar KeyError, sedangkan jika Anda menggunakan metode dict get()Anda dapat menentukan default. Saya menetapkan default string kosong sehingga split () tidak melempar AttributeError. Itu saja.
penulis ben
@ Ben. Terima kasih itu berhasil untuk saya. Anda juga dapat menjawab pertanyaan ini saya yakin ini adalah perpanjangan dari pertanyaan ini hanya stackoverflow.com/questions/10410982/… . Bisakah Anda memberi saya solusi untuk ini.
the_game
1
Ini bekerja dengan baik. has_key()tidak digunakan lagi karena mendukung key in d. Tapi saya tahu Anda baru saja mengambil dari jawaban ha22109. Satu pertanyaan: mengapa menggunakan request.META['PATH_INFO']saat Anda bisa menggunakan request.path_info(lebih pendek)?
Nick
19

Saya tahu pertanyaan ini sudah cukup tua sekarang, tetapi masih valid. Saya yakin ini adalah cara paling benar untuk melakukan ini. Ini pada dasarnya sama dengan metode Greg, tetapi diformulasikan sebagai kelas yang dapat diperpanjang agar mudah digunakan kembali.

from django.contrib.admin import SimpleListFilter
from django.utils.encoding import force_text
from django.utils.translation import ugettext as _

class DefaultListFilter(SimpleListFilter):
    all_value = '_all'

    def default_value(self):
        raise NotImplementedError()

    def queryset(self, request, queryset):
        if self.parameter_name in request.GET and request.GET[self.parameter_name] == self.all_value:
            return queryset

        if self.parameter_name in request.GET:
            return queryset.filter(**{self.parameter_name:request.GET[self.parameter_name]})

        return queryset.filter(**{self.parameter_name:self.default_value()})

    def choices(self, cl):
        yield {
            'selected': self.value() == self.all_value,
            'query_string': cl.get_query_string({self.parameter_name: self.all_value}, []),
            'display': _('All'),
        }
        for lookup, title in self.lookup_choices:
            yield {
                'selected': self.value() == force_text(lookup) or (self.value() == None and force_text(self.default_value()) == force_text(lookup)),
                'query_string': cl.get_query_string({
                    self.parameter_name: lookup,
                }, []),
                'display': title,
            }

class StatusFilter(DefaultListFilter):
    title = _('Status ')
    parameter_name = 'status__exact'

    def lookups(self, request, model_admin):
        return ((0,'activate'), (1,'pending'), (2,'rejected'))

    def default_value(self):
        return 1

class MyModelAdmin(admin.ModelAdmin):
    list_filter = (StatusFilter,)
Andrew Hows
sumber
8

Berikut adalah solusi umum saya menggunakan redirect, itu hanya memeriksa apakah ada parameter GET, jika tidak ada maka itu mengalihkan dengan parameter get default. Saya juga memiliki set list_filter sehingga mengambilnya dan menampilkan default.

from django.shortcuts import redirect

class MyModelAdmin(admin.ModelAdmin):   

    ...

    list_filter = ('status', )

    def changelist_view(self, request, extra_context=None):
        referrer = request.META.get('HTTP_REFERER', '')
        get_param = "status__exact=5"
        if len(request.GET) == 0 and '?' not in referrer:
            return redirect("{url}?{get_parms}".format(url=request.path, get_parms=get_param))
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)

Satu-satunya peringatan adalah ketika Anda melakukan akses langsung ke halaman dengan "?" ada di url, tidak ada set HTTP_REFERER sehingga akan menggunakan parameter default dan pengalihan. Ini bagus untuk saya, ini berfungsi dengan baik saat Anda mengeklik melalui filter admin.

MEMPERBARUI :

Untuk mengatasi peringatan tersebut, saya akhirnya menulis fungsi filter khusus yang menyederhanakan fungsi changelist_view. Berikut filternya:

class MyModelStatusFilter(admin.SimpleListFilter):
    title = _('Status')
    parameter_name = 'status'

    def lookups(self, request, model_admin):  # Available Values / Status Codes etc..
        return (
            (8, _('All')),
            (0, _('Incomplete')),
            (5, _('Pending')),
            (6, _('Selected')),
            (7, _('Accepted')),
        )

    def choices(self, cl):  # Overwrite this method to prevent the default "All"
        from django.utils.encoding import force_text
        for lookup, title in self.lookup_choices:
            yield {
                'selected': self.value() == force_text(lookup),
                'query_string': cl.get_query_string({
                    self.parameter_name: lookup,
                }, []),
                'display': title,
            }

    def queryset(self, request, queryset):  # Run the queryset based on your lookup values
        if self.value() is None:
            return queryset.filter(status=5)
        elif int(self.value()) == 0:
            return queryset.filter(status__lte=4)
        elif int(self.value()) == 8:
            return queryset.all()
        elif int(self.value()) >= 5:
            return queryset.filter(status=self.value())
        return queryset.filter(status=5)

Dan changelist_view sekarang hanya meneruskan parameter default jika tidak ada. Idenya adalah untuk menghilangkan kemampuan filter generik untuk melihat semua dengan menggunakan parameter no get. Untuk melihat semua, saya menetapkan status = 8 untuk tujuan itu .:

class MyModelAdmin(admin.ModelAdmin):   

    ...

    list_filter = ('status', )

    def changelist_view(self, request, extra_context=None):
        if len(request.GET) == 0:
            get_param = "status=5"
            return redirect("{url}?{get_parms}".format(url=request.path, get_parms=get_param))
        return super(MyModelAdmin, self).changelist_view(request, extra_context=extra_context)
radtek
sumber
Saya memiliki perbaikan untuk peringatan saya, filter khusus. Saya akan menyajikannya sebagai solusi alternatif.
radtek
Terima kasih, menurut saya pengalihan adalah solusi yang paling bersih dan sederhana. Saya juga tidak mengerti "peringatan". Saya selalu mendapatkan hasil yang diinginkan, baik dengan mengklik atau menggunakan link langsung (saya tidak menggunakan filter kustom).
Dennis Golomazov
6
def changelist_view( self, request, extra_context = None ):
    default_filter = False
    try:
        ref = request.META['HTTP_REFERER']
        pinfo = request.META['PATH_INFO']
        qstr = ref.split( pinfo )

        if len( qstr ) < 2:
            default_filter = True
    except:
        default_filter = True

    if default_filter:
        q = request.GET.copy()
        q['registered__exact'] = '1'
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()

    return super( InterestAdmin, self ).changelist_view( request, extra_context = extra_context )
pengguna1163719
sumber
4

Anda cukup menggunakan return queryset.filter()atau if self.value() is Nonedan metode Override dari SimpleListFilter

from django.utils.encoding import force_text

def choices(self, changelist):
    for lookup, title in self.lookup_choices:
        yield {
            'selected': force_text(self.value()) == force_text(lookup),
            'query_string': changelist.get_query_string(
                {self.parameter_name: lookup}, []
            ),
            'display': title,
        }
Jay Dave
sumber
3

Perhatikan bahwa jika alih-alih memilih nilai filter sebelumnya, Anda ingin selalu memfilter data terlebih dahulu sebelum menampilkannya di admin, Anda harus mengganti ModelAdmin.queryset()metode tersebut.

akaihola
sumber
Ini adalah solusi yang cukup bersih dan cepat meskipun masih menimbulkan masalah. Ketika opsi pemfilteran diaktifkan di admin, pengguna mungkin mendapatkan hasil yang tampaknya salah. Jika queryset yang diganti berisi klausa .exclude (), maka record yang ditangkap olehnya tidak akan pernah dicantumkan, tetapi opsi pemfilteran admin untuk menampilkannya secara eksplisit akan tetap ditawarkan oleh UI admin.
Tomas Andrle
Ada jawaban lain yang lebih benar dengan suara yang lebih rendah yang berlaku untuk situasi ini karena OP telah dengan jelas meminta agar dia akan memasang filter di mana queryset akan menjadi solusi yang salah seperti yang juga ditunjukkan oleh @TomasAndrle di atas.
eskhool
Terima kasih telah menunjukkan hal ini pada @eskhool, saya mencoba memberi suara negatif pada jawaban saya menjadi nol tetapi tampaknya tidak diperbolehkan untuk merendahkan diri sendiri.
akaihola
3

Sedikit perbaikan pada jawaban Greg menggunakan DjangoChoices, Python> = 2.5 dan tentu saja Django> = 1.4.

from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter

class OrderStatusFilter(SimpleListFilter):
    title = _('Status')

    parameter_name = 'status__exact'
    default_status = OrderStatuses.closed

    def lookups(self, request, model_admin):
        return (('all', _('All')),) + OrderStatuses.choices

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

    def queryset(self, request, queryset):
        if self.value() in OrderStatuses.values:
            return queryset.filter(status=self.value())
        elif self.value() is None:
            return queryset.filter(status=self.default_status)


class Admin(admin.ModelAdmin):
    list_filter = [OrderStatusFilter] 

Terima kasih kepada Greg untuk solusi yang bagus!

Ben Konrath
sumber
2

Saya tahu itu bukan solusi terbaik, tetapi saya mengubah index.html di template admin, baris 25 dan 37 seperti ini:

25: <th scope="row"><a href="{{ model.admin_url }}{% ifequal model.name "yourmodelname" %}?yourflag_flag__exact=1{% endifequal %}">{{ model.name }}</a></th>

37: <td><a href="{{ model.admin_url }}{% ifequal model.name "yourmodelname" %}?yourflag__exact=1{% endifequal %}" class="changelink">{% trans 'Change' %}</a></td>

Mauro De Giorgi
sumber
1

Saya harus membuat modifikasi agar pemfilteran berfungsi dengan benar. Solusi sebelumnya berfungsi untuk saya saat halaman dimuat. Jika 'tindakan' dilakukan, filter kembali ke 'Semua' dan bukan default saya. Solusi ini memuat halaman perubahan admin dengan filter default, tetapi juga mempertahankan perubahan filter atau filter saat ini ketika aktivitas lain terjadi di halaman. Saya belum menguji semua kasus, tetapi pada kenyataannya mungkin membatasi pengaturan filter default hanya terjadi saat halaman dimuat.

def changelist_view(self, request, extra_context=None):
    default_filter = False

    try:
        ref = request.META['HTTP_REFERER']
        pinfo = request.META['PATH_INFO']
        qstr = ref.split(pinfo)
        querystr = request.META['QUERY_STRING']

        # Check the QUERY_STRING value, otherwise when
        # trying to filter the filter gets reset below
        if querystr is None:
            if len(qstr) < 2 or qstr[1] == '':
                default_filter = True
    except:
        default_filter = True

    if default_filter:
        q = request.GET.copy()
        q['registered__isnull'] = 'True'
        request.GET = q
        request.META['QUERY_STRING'] = request.GET.urlencode()

    return super(MyAdmin, self).changelist_view(request, extra_context=extra_context)
mhck
sumber
1

Agak di luar topik tetapi pencarian saya untuk pertanyaan serupa membawa saya ke sini. Saya ingin memiliki kueri default berdasarkan tanggal (yaitu jika tidak ada masukan yang disediakan, tampilkan hanya objek dengan timestamp'Hari Ini'), yang sedikit memperumit pertanyaan. Inilah yang saya dapatkan:

from django.contrib.admin.options import IncorrectLookupParameters
from django.core.exceptions import ValidationError

class TodayDefaultDateFieldListFilter(admin.DateFieldListFilter):
    """ If no date is query params are provided, query for Today """

    def queryset(self, request, queryset):
        try:
            if not self.used_parameters:
                now = datetime.datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
                self.used_parameters = {
                    ('%s__lt' % self.field_path): str(now + datetime.timedelta(days=1)),
                    ('%s__gte' % self.field_path): str(now),
                }
                # Insure that the dropdown reflects 'Today'
                self.date_params = self.used_parameters
            return queryset.filter(**self.used_parameters)
        except ValidationError, e:
            raise IncorrectLookupParameters(e)

class ImagesAdmin(admin.ModelAdmin):
    list_filter = (
        ('timestamp', TodayDefaultDateFieldListFilter),
    )

Ini adalah penggantian sederhana dari default DateFieldListFilter. Dengan mengatur self.date_params, ini memastikan bahwa dropdown filter akan diperbarui ke opsi apa pun yang cocok dengan self.used_parameters. Untuk alasan ini, Anda harus memastikan bahwa self.used_parameterspersis apa yang akan digunakan oleh salah satu pilihan dropdown tersebut (yaitu, cari tahudate_params jadinya saat menggunakan 'Hari Ini' atau '7 Hari Terakhir' dan membuatself.used_parameters untuk mencocokkannya).

Ini dibangun untuk bekerja dengan Django 1.4.10

alukach.dll
sumber
1

Ini mungkin utas lama, tetapi saya pikir saya akan menambahkan solusi saya karena saya tidak dapat menemukan jawaban yang lebih baik di pencarian google.

Lakukan apa (tidak yakin apakah Deminic Rodger, atau ha22109) dijawab di ModelAdmin untuk changelist_view

class MyModelAdmin(admin.ModelAdmin):   
    list_filter = (CustomFilter,)

    def changelist_view(self, request, extra_context=None):

        if not request.GET.has_key('decommissioned__exact'):

            q = request.GET.copy()
            q['decommissioned__exact'] = 'N'
            request.GET = q
            request.META['QUERY_STRING'] = request.GET.urlencode()
        return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context)

Kemudian kita perlu membuat SimpleListFilter kustom

class CustomFilter(admin.SimpleListFilter):
    title = 'Decommissioned'
    parameter_name = 'decommissioned'  # i chose to change it

def lookups(self, request, model_admin):
    return (
        ('All', 'all'),
        ('1', 'Decommissioned'),
        ('0', 'Active (or whatever)'),
    )

# had to override so that we could remove the default 'All' option
# that won't work with our default filter in the ModelAdmin class
def choices(self, cl):
    yield {
        'selected': self.value() is None,
        'query_string': cl.get_query_string({}, [self.parameter_name]),
        # 'display': _('All'),
    }
    for lookup, title in self.lookup_choices:
        yield {
            'selected': self.value() == lookup,
            'query_string': cl.get_query_string({
                self.parameter_name: lookup,
            }, []),
            'display': title,
        }

def queryset(self, request, queryset):
    if self.value() == '1':
        return queryset.filter(decommissioned=1)
    elif self.value() == '0':
        return queryset.filter(decommissioned=0)
    return queryset
warath-coder
sumber
Saya menemukan saya perlu menggunakan fungsi 'force_text' (alias force_unicode) dalam panggilan hasil dalam fungsi pilihan, jika tidak, opsi filter yang dipilih tidak akan muncul sebagai 'dipilih'. Yaitu "'dipilih': self.value () == force_text (lookup),"
MagicLAMP
1

Inilah versi Terbersih yang dapat saya buat dari filter dengan 'Semua' yang didefinisikan ulang dan nilai Default yang dipilih.

Jika menunjukkan kepada saya secara default, Perjalanan sedang berlangsung.

class HappeningTripFilter(admin.SimpleListFilter):
    """
    Filter the Trips Happening in the Past, Future or now.
    """
    default_value = 'now'
    title = 'Happening'
    parameter_name = 'happening'

    def lookups(self, request, model_admin):
        """
        List the Choices available for this filter.
        """
        return (
            ('all', 'All'),
            ('future', 'Not yet started'),
            ('now', 'Happening now'),
            ('past', 'Already finished'),
        )

    def choices(self, changelist):
        """
        Overwrite this method to prevent the default "All".
        """
        value = self.value() or self.default_value
        for lookup, title in self.lookup_choices:
            yield {
                'selected': value == force_text(lookup),
                'query_string': changelist.get_query_string({
                    self.parameter_name: lookup,
                }, []),
                'display': title,
            }

    def queryset(self, request, queryset):
        """
        Returns the Queryset depending on the Choice.
        """
        value = self.value() or self.default_value
        now = timezone.now()
        if value == 'future':
            return queryset.filter(start_date_time__gt=now)
        if value == 'now':
            return queryset.filter(start_date_time__lte=now, end_date_time__gte=now)
        if value == 'past':
            return queryset.filter(end_date_time__lt=now)
        return queryset.all()
Jerome Millet
sumber
0

Membuat sub-kelas Filter yang dapat digunakan kembali, terinspirasi oleh beberapa jawaban di sini (kebanyakan Greg).

Keuntungan:

Dapat digunakan kembali - Dapat dicolokkan di semua ModelAdminkelas standar

Dapat diperpanjang - Mudah untuk menambahkan logika tambahan / khususQuerySet pemfilteran

Mudah digunakan - Dalam bentuk paling dasar, hanya satu atribut khusus dan satu metode khusus yang perlu diterapkan (selain yang diperlukan untuk subkelas SimpleListFilter)

Admin intuitif - Tautan filter "Semua" berfungsi seperti yang diharapkan; seperti yang lainnya

Tidak ada pengalihan - Tidak perlu memeriksa GETmuatan permintaan, agnostik HTTP_REFERER(atau hal terkait permintaan lainnya, dalam bentuk dasarnya)

Tidak ada manipulasi tampilan (daftar perubahan) - Dan tidak ada manipulasi template (amit-amit)

Kode:

(sebagian besar importhanya untuk petunjuk dan pengecualian tipe)

from typing import List, Tuple, Any

from django.contrib.admin.filters import SimpleListFilter
from django.contrib.admin.options import IncorrectLookupParameters
from django.contrib.admin.views.main import ChangeList
from django.db.models.query import QuerySet
from django.utils.encoding import force_str
from django.utils.translation import gettext_lazy as _
from django.core.exceptions import ValidationError


class PreFilteredListFilter(SimpleListFilter):

    # Either set this or override .get_default_value()
    default_value = None

    no_filter_value = 'all'
    no_filter_name = _("All")

    # Human-readable title which will be displayed in the
    # right admin sidebar just above the filter options.
    title = None

    # Parameter for the filter that will be used in the URL query.
    parameter_name = None

    def get_default_value(self):
        if self.default_value is not None:
            return self.default_value
        raise NotImplementedError(
            'Either the .default_value attribute needs to be set or '
            'the .get_default_value() method must be overridden to '
            'return a URL query argument for parameter_name.'
        )

    def get_lookups(self) -> List[Tuple[Any, str]]:
        """
        Returns a list of tuples. The first element in each
        tuple is the coded value for the option that will
        appear in the URL query. The second element is the
        human-readable name for the option that will appear
        in the right sidebar.
        """
        raise NotImplementedError(
            'The .get_lookups() method must be overridden to '
            'return a list of tuples (value, verbose value).'
        )

    # Overriding parent class:
    def lookups(self, request, model_admin) -> List[Tuple[Any, str]]:
        return [(self.no_filter_value, self.no_filter_name)] + self.get_lookups()

    # Overriding parent class:
    def queryset(self, request, queryset: QuerySet) -> QuerySet:
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        if self.value() is None:
            return self.get_default_queryset(queryset)
        if self.value() == self.no_filter_value:
            return queryset.all()
        return self.get_filtered_queryset(queryset)

    def get_default_queryset(self, queryset: QuerySet) -> QuerySet:
        return queryset.filter(**{self.parameter_name: self.get_default_value()})

    def get_filtered_queryset(self, queryset: QuerySet) -> QuerySet:
        try:
            return queryset.filter(**self.used_parameters)
        except (ValueError, ValidationError) as e:
            # Fields may raise a ValueError or ValidationError when converting
            # the parameters to the correct type.
            raise IncorrectLookupParameters(e)

    # Overriding parent class:
    def choices(self, changelist: ChangeList):
        """
        Overridden to prevent the default "All".
        """
        value = self.value() or force_str(self.get_default_value())
        for lookup, title in self.lookup_choices:
            yield {
                'selected': value == force_str(lookup),
                'query_string': changelist.get_query_string({self.parameter_name: lookup}),
                'display': title,
            }

Contoh penggunaan lengkap:

from django.contrib import admin
from .models import SomeModelWithStatus


class StatusFilter(PreFilteredListFilter):
    default_value = SomeModelWithStatus.Status.FOO
    title = _('Status')
    parameter_name = 'status'

    def get_lookups(self):
        return SomeModelWithStatus.Status.choices


@admin.register(SomeModelWithStatus)
class SomeModelAdmin(admin.ModelAdmin):
    list_filter = (StatusFilter, )

Semoga ini bisa membantu seseorang; umpan balik selalu dihargai.

JohnGalt
sumber