Filtre par défaut dans l'admin Django

94

Comment puis-je changer le choix de filtre par défaut de «TOUS»? J'ai un champ nommé statusqui a trois valeurs: activate, pendinget rejected. Lorsque j'utilise list_filterdans l'admin Django, le filtre est défini par défaut sur «Tous» mais je souhaite le définir sur en attente par défaut.

ha22109
la source

Réponses:

102

Pour ce faire et avoir un lien «Tous» utilisable dans votre barre latérale (c'est-à-dire un lien qui montre tout plutôt que d'afficher en attente), vous devez créer un filtre de liste personnalisé, héritant de django.contrib.admin.filters.SimpleListFilteret filtrant sur «en attente» par défaut. Quelque chose de ce genre devrait fonctionner:

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: Nécessite Django 1.4 (merci Simon)

Greg
la source
3
C'est la solution la plus propre de toutes, mais elle a le moins de votes positifs ... elle nécessite Django 1.4, bien que cela devrait être acquis maintenant.
Simon
@Greg Comment supprimer complètement la fonctionnalité du filtre et l'onglet de filtre de la page d'administration?
2
Cette solution présente un petit inconvénient. Lorsque les filtres sont vides (filtre "en attente" réellement utilisé), Django 1.8 détermine de manière incorrecte le nombre de résultats complet et n'affiche pas le nombre de résultats si show_full_result_count vaut True (par défaut). -
Alexander Fedotov
Notez que si vous ne parvenez pas à remplacer la choicesméthode dans la solution, elle continuera à ajouter sa propre option Tous en haut de la liste de choix.
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
la source
18
Cette solution présente l'inconvénient que, bien que le choix "Tous" soit toujours affiché dans l'interface utilisateur, sa sélection applique toujours le filtrage par défaut.
akaihola
j'ai la même question, mais je peux comprendre la rediffusion ... désolé je suis nouveau avec Django ... mais peut-être que cela fonctionnera blog.dougalmatthews.com/2008/10
...
C'est bien mais j'avais besoin de voir le paramètre get dans l'url afin que mon filtre puisse le récupérer et l'afficher sélectionné. Publication de ma solution sous peu.
radtek le
explication manquante. le simple fait de publier un morceau de code peut ne pas aider tout le monde. en plus cela ne fonctionne pas et sans un peu de contexte, il est difficile de savoir pourquoi
EvilSmurf
19

A pris la réponse de ha22109 ci-dessus et modifié pour permettre la sélection de "Tous" en comparant HTTP_REFERERet 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)
iridescent
la source
3
Cela a cassé pour moi car HTTP_REFERER n'était pas toujours présent. J'ai fait 'referer = request.META.get (' HTTP_REFERER ',' '); test = referer.split (request.META ['PATH_INFO']) `
ben author
@Ben J'utilise vos deux lignes referer = request.META.get ('HTTP_REFERER', '') test = referer.split (request.META ['PATH_INFO']). Je ne parle pas beaucoup de HTTP_REFERER. Le problème est-il complètement résolu à partir de ces lignes si HTTP_REFERER n'est pas présent.
the_game
@the_game ouais, l'idée est que si vous utilisez des crochets pour tenter d'accéder à une clé qui n'existe pas, cela lance KeyError, alors que si vous utilisez la get()méthode de dict, vous pouvez spécifier une valeur par défaut. J'ai spécifié une valeur par défaut de chaîne vide pour que split () ne lance pas AttributeError. C'est tout.
Ben auteur
@Ben .Merci que ça marche pour moi. Pouvez-vous également répondre à cette question, je crois que c'est une extension à cette question uniquement stackoverflow.com/questions/10410982/… . Pouvez-vous s'il vous plaît me fournir une solution pour cela.
the_game
1
Cela fonctionne bien. has_key()est déconseillé au profit de key in d, cependant. Mais je sais que vous venez de prendre la réponse de ha22109. Une question: pourquoi utiliser request.META['PATH_INFO']alors que vous pourriez simplement utiliser request.path_info(plus court)?
Nick
19

Je sais que cette question est assez ancienne maintenant, mais elle est toujours valable. Je pense que c'est la manière la plus correcte de procéder. C'est essentiellement la même que la méthode de Greg, mais formulée comme une classe extensible pour une réutilisation facile.

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
la source
8

Voici ma solution générique utilisant la redirection, elle vérifie simplement s'il existe des paramètres GET, s'il n'en existe pas, elle redirige avec le paramètre get par défaut. J'ai également un list_filter défini pour qu'il le récupère et affiche la valeur par défaut.

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)

La seule mise en garde est lorsque vous accédez directement à la page avec "?" présent dans l'url, il n'y a pas de jeu HTTP_REFERER donc il utilisera le paramètre par défaut et redirigera. Cela me convient, cela fonctionne très bien lorsque vous cliquez sur le filtre d'administration.

MISE À JOUR :

Afin de contourner la mise en garde, j'ai fini par écrire une fonction de filtre personnalisée qui simplifiait la fonctionnalité changelist_view. Voici le filtre:

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)

Et le changelist_view ne transmet désormais le paramètre par défaut que si aucun n'est présent. L'idée était de se débarrasser de la capacité des filtres génériques à tout afficher en n'utilisant aucun paramètre get. Pour voir tout, j'ai attribué le statut = 8 à cette fin:

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
la source
J'ai un correctif pour ma mise en garde, un filtre personnalisé. Je vais le présenter comme une solution alternative.
radtek
Merci, je trouve que la redirection est la solution la plus propre et la plus simple. Je ne comprends pas non plus «la mise en garde». J'obtiens toujours le résultat souhaité, que ce soit en cliquant ou en utilisant un lien direct (je n'ai pas utilisé le filtre personnalisé).
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 )
utilisateur1163719
la source
4

Vous pouvez simplement utiliser la méthode return queryset.filter()or if self.value() is Noneet Override de 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
la source
3

Notez que si au lieu de présélectionner une valeur de filtre, vous souhaitez toujours pré-filtrer les données avant de les afficher dans l'administrateur, vous devez remplacer la ModelAdmin.queryset()méthode à la place.

Akaihola
la source
C'est une solution assez propre et rapide bien qu'elle puisse toujours causer des problèmes. Lorsque les options de filtrage sont activées dans l'administrateur, l'utilisateur peut obtenir des résultats apparemment incorrects. Si le jeu de requêtes surchargé contient une clause .exclude (), les enregistrements interceptés par celle-ci ne seront jamais répertoriés, mais les options de filtrage d'administration pour les afficher explicitement seront toujours proposées par l'interface utilisateur d'administration.
Tomas Andrle
Il y a d'autres réponses plus correctes avec des votes inférieurs qui s'appliquent à cette situation puisque l'OP a clairement demandé qu'il va mettre un filtre dans lequel un jeu de requêtes serait la mauvaise solution comme l'a également souligné @TomasAndrle ci-dessus.
eskhool
Merci d'avoir signalé cela @eskhool, j'ai essayé de rejeter ma réponse à zéro, mais il semble qu'il n'est pas permis de voter soi-même.
akaihola
3

Une légère amélioration par rapport à la réponse de Greg en utilisant DjangoChoices, Python> = 2.5 et bien sûr 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] 

Merci à Greg pour la belle solution!

Ben Konrath
la source
2

Je sais que ce n'est pas la meilleure solution, mais j'ai changé l'index.html dans le modèle d'administration, lignes 25 et 37 comme ceci:

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
la source
1

J'ai dû faire une modification pour que le filtrage fonctionne correctement. La solution précédente a fonctionné pour moi lorsque la page s'est chargée. Si une «action» était effectuée, le filtre revenait à «Tous» et non à ma valeur par défaut. Cette solution charge la page de modification de l'administrateur avec le filtre par défaut, mais conserve également les modifications de filtre ou le filtre actuel lorsqu'une autre activité se produit sur la page. Je n'ai pas testé tous les cas, mais en réalité, cela peut limiter le réglage d'un filtre par défaut pour qu'il se produise uniquement lorsque la page se charge.

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
la source
1

Un peu hors sujet mais ma recherche d'une question similaire m'a conduit ici. Je cherchais à avoir une requête par défaut par date (c'est-à-dire si aucune entrée n'est fournie, n'afficher que les objets avec timestamp«Aujourd'hui»), ce qui complique un peu la question. Voici ce que j'ai trouvé:

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),
    )

Il s'agit d'un simple remplacement de la valeur par défaut DateFieldListFilter. En définissant self.date_params, il garantit que la liste déroulante du filtre sera mise à jour selon l'option qui correspond au self.used_parameters. Pour cette raison, vous devez vous assurer que le self.used_parameterssont exactement ce qui serait utilisé par l'une de ces sélections déroulantes (c'est-à-dire, découvrez ce que date_paramsserait lorsque vous utilisez "Aujourd'hui" ou "7 derniers jours" et construisez le self.used_parameterspour correspondre à ceux-ci).

Cela a été conçu pour fonctionner avec Django 1.4.10

Alukach
la source
1

Il s'agit peut-être d'un ancien fil de discussion, mais je pensais ajouter ma solution car je ne pouvais pas trouver de meilleures réponses sur les recherches Google.

Faites quoi (je ne sais pas si son Deminic Rodger, ou ha22109) a répondu dans ModelAdmin pour 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)

Ensuite, nous devons créer un SimpleListFilter personnalisé

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
codeur de guerre
la source
J'ai trouvé que j'avais besoin d'utiliser la fonction 'force_text' (aka force_unicode) dans l'appel de rendement dans la fonction de choix, sinon l'option de filtre sélectionnée ne s'afficherait pas comme 'sélectionnée'. C'est "'selected': self.value () == force_text (lookup),"
MagicLAMP
1

Voici la version la plus propre que j'ai pu générer d'un filtre avec un 'Tout' redéfini et une valeur par défaut sélectionnée.

Si me montre par défaut les voyages en cours.

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()
Jérôme Millet
la source
0

Création d'une sous-classe de filtre réutilisable, inspirée de certaines des réponses ici (principalement celles de Greg).

Avantages:

Réutilisable - enfichable dans toutes les ModelAdminclasses standard

Extensible - Facile à ajouter une logique supplémentaire / personnalisée pour le QuerySetfiltrage

Facile à utiliser - Dans sa forme la plus basique, un seul attribut personnalisé et une méthode personnalisée doivent être implémentés (en dehors de ceux requis pour la sous-classification SimpleListFilter)

Administration intuitive - Le lien de filtre «Tous» fonctionne comme prévu; comme tous les autres

Pas de redirection - Pas besoin d'inspecter la GETcharge utile de la demande, indépendamment de HTTP_REFERER(ou de tout autre élément lié à la demande, dans sa forme de base)

Aucune manipulation de vue (liste de modifications) - Et aucune manipulation de modèle (à Dieu ne plaise)

Code:

(la plupart des imports sont juste pour les conseils de type et les exceptions)

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,
            }

Exemple d'utilisation complet:

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, )

J'espère que cela aide quelqu'un; rétroaction toujours appréciée.

JohnGalt
la source