73 votes

Filtre personnalisé dans Django Admin sur Django 1.3 ou inférieur

Comment puis-je ajouter un filtre personnalisé à django admin (les filtres qui apparaissent sur le côté droit du tableau de bord d'un modèle) ? Je sais qu'il est facile d'inclure un filtre basé sur un champ de ce modèle, mais qu'en est-il d'un champ "calculé" comme celui-ci :

class NewsItem(models.Model):
    headline = models.CharField(max_length=4096, blank=False)
    byline_1 = models.CharField(max_length=4096, blank=True)
    dateline = models.DateTimeField(help_text=_("date/time that appears on article"))
    body_copy = models.TextField(blank=False)

    when_to_publish = models.DateTimeField(verbose_name="When to publish",  blank=True, null=True)

    # HOW CAN I HAVE "is_live" as part of the admin filter?  It's a calculated state!!
    def is_live(self):
        if self.when_to_publish is not None:
            if ( self.when_to_publish < datetime.now() ):
                return """ <img alt="True" src="/media/img/admin/icon-yes.gif"/> """
        else:
            return """ <img alt="False" src="/media/img/admin/icon-no.gif"/> """      

    is_live.allow_tags = True

class NewsItemAdmin(admin.ModelAdmin):
    form = NewsItemAdminForm
    list_display = ('headline', 'id', 'is_live')
    list_filter = ('is_live')  #  how can i make this work??

57voto

Mark Ellul Points 1062

Merci à gpilotino de m'avoir poussé dans la bonne direction pour mettre en œuvre ce projet.

J'ai remarqué que le code de la question utilise une date pour savoir quand il est en ligne. J'ai donc utilisé le DateFieldFilterSpec et l'ai sous-classé.

from django.db import models
from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec,DateFieldFilterSpec
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext as _
from datetime import datetime

class IsLiveFilterSpec(DateFieldFilterSpec):
    """
    Adds filtering by future and previous values in the admin
    filter sidebar. Set the is_live_filter filter in the model field attribute
    'is_live_filter'.    my_model_field.is_live_filter = True
    """

    def __init__(self, f, request, params, model, model_admin):
        super(IsLiveFilterSpec, self).__init__(f, request, params, model,
                                               model_admin)
        today = datetime.now()
        self.links = (
            (_('Any'), {}),
            (_('Yes'), {'%s__lte' % self.field.name: str(today),
                       }),
            (_('No'), {'%s__gte' % self.field.name: str(today),
                    }),

        )

    def title(self):
        return "Is Live"

# registering the filter
FilterSpec.filter_specs.insert(0, (lambda f: getattr(f, 'is_live_filter', False),
                               IsLiveFilterSpec))

Pour l'utiliser, vous pouvez mettre le code ci-dessus dans un filters.py, et l'importer dans le modèle auquel vous voulez ajouter le filtre

23voto

gpilotino Points 5644

Vous devez écrire un FilterSpec personnalisé (qui n'est documenté nulle part). Regardez ici pour un exemple :

http://www.djangosnippets.org/snippets/1051/

9voto

matley Points 300

Dans la version de développement actuelle de Django, il existe un support pour les filtres personnalisés : https://docs.djangoproject.com/en/dev/ref/contrib/admin/#django.contrib.admin.ModelAdmin.list_filter

3voto

Daniel Roseman Points 199743

Vous ne pouvez pas, malheureusement. Actuellement, les éléments qui ne sont pas des champs ne peuvent pas être utilisés comme entrées de list_filter.

Notez que votre classe d'administration n'aurait pas fonctionné même s'il s'agissait d'un champ, car un tuple à un seul élément nécessite une virgule : ('is_live',)

2voto

peter2108 Points 581

L'utilisateur fournit des marchandises à certains pays sans frais de port. Je voulais filtrer ces pays :

Tous - tous les pays, Oui - sans frais de port, Non - frais de port facturés.

La réponse principale à cette question n'a pas fonctionné pour moi (Django 1.3) je pense que c'est parce qu'il n'y avait pas de field_path fourni dans le paramètre __init__ méthode. Il a également sous-classé DateFieldFilterSpec . El postage Le champ est un FloatField

from django.contrib.admin.filterspecs import FilterSpec

class IsFreePostage(FilterSpec):

    def __init__(self, f, request, params, model, model_admin, field_path=None):
        super(IsFreePostage, self).__init__(f, request, params, model,
            model_admin, field_path)

        self.removes = {
            'Yes': ['postage__gt'],
            'No': ['postage__exact'],
            'All': ['postage__exact', 'postage__gt'] }

        self.links = (
            ('All', {}),
            ('Yes', {'postage__exact': 0}),
            ('No', {'postage__gt': 0}))

        if request.GET.has_key('postage__exact'):
            self.ttl = 'Yes'
        elif request.GET.has_key('postage__gt'):
            self.ttl = 'No'
        else:
            self.ttl = 'All'

    def choices(self, cl):
        for title, param_dict in self.links:
            yield {'selected': title == self.ttl,
                   'query_string': cl.get_query_string(param_dict,
                       self.removes[title]),
                   'display': title}
    def title(self):
        return 'Free Postage'

FilterSpec.filter_specs.insert(0,
    (lambda f: getattr(f, 'free_postage', False), IsFreePostage))

Dans self.links, nous fournissons des dicts, utilisés pour construire des chaînes de requête HTTP telles que ?postage__exact=0 pour chacun des filtres possibles. Filtres Je pense sont cumulatives. Ainsi, si une requête précédente demandait "Non" et que nous avons maintenant une requête "Oui", nous devons supprimer la requête "Non". la demande "Non". self.removes précise ce qui doit être supprimé pour chaque requête. Le site choices construit les chaînes de requête, indique quel filtre a été sélectionné et définit le nom affiché du filtre.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X