2010-06-18 4 views
19

Je sais que je l'ai déjà réussi à le faire, mais ne me souviens pas comment, ni je ne peux trouver aucune documentation sur ce ..filtre par défaut Django admin

Comment appliquer un filtre par défaut sur une vue de liste d'objets dans l'administrateur?

J'ai une application qui liste des citations et ces citations ont un statut (ex: accepté, rejeté, en attente ..).

Je veux que le filtre défini sur l'état = « accepté » par défaut qui est ..

+1

Juste pour l'enregistrement de cette question [est correctement répondu ici] (http://stackoverflow.com/questions/851636/default-filter-in-django-admin/3783930#3783930) –

+1

Copie possible de [Filtre par défaut dans l'administration Django] (https://stackoverflow.com/questions/851636/default-filter-in- django-admin) –

Répondre

6

Vous pouvez remplacer le queryset

class QuoteAdmin(admin.ModelAdmin): 
    def get_queryset(self, request): 
     return super(QuoteAdmin,self).get_queryset(request).filter(status="accepted") 

Cependant en redéfinissant la queryset vous ne serez jamais en mesure de voir les citations qui n'ont pas le statut "accepté".

Vous pouvez également créer un lien vers l'URL suivante en ajoutant le filtre aux paramètres GET.

/admin/myapp/quote/?status=accepted 
7

Enfin, voici ce que je cherchais:

def changelist_view(self, request, extra_context=None): 
    if not request.GET.has_key('status__exact'): 
     q = request.GET.copy() 
     q['status__exact'] = '1' 
     request.GET = q 
     request.META['QUERY_STRING'] = request.GET.urlencode() 
    return super(SoumissionAdmin,self).changelist_view(request, extra_context=extra_context) 

L'autre façon, avec la méthode queryset dans la classe d'administration ne fonctionne pas. En fait, il filtre les résultats, mais il laisse la fonctionnalité du filtre brisée.

La solution que j'ai trouvé est pas parfait non plus, il est impossible lorsque vous l'utilisez pour sélectionner « All/filtre. Dans mon cas, ce n'est pas dramatique et il sera assez bon si ..

2

Je pense Je l'ai trouvé un moyen de le faire sans limiter l'utilisateur. Il suffit de regarder au referer pour déterminer si l'utilisateur vient d'arriver à cette page. Si donc les rediriger vers l'URL par défaut que vous voulez en fonction de ce filtre.

def changelist_view(self, request, extra_context=None): 
    try: 
     test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO']) 
     if test and test[-1] and not test[-1].startswith('?') and not request.GET.has_key('status__exact'): 
      return HttpResponseRedirect("/admin/app/model/?status__exact=1") 
    except: pass # In case there is no referer 
    return super(MyModelAdmin,self).changelist_view(request, extra_context=extra_context) 
+0

C'est tout à fait le hack codé en dur, mais cette réponse fonctionne. Je l'ai fait juste le moindre hackish en remplaçant "/ admin/app/model /" par request.path et concaténé mon équivalent de "? Status__exact = 1" avant d'envoyer la réponse http redirect – Archie1986

17

Une approche un peu plus réutilisable:

class DefaultFilterMixIn(admin.ModelAdmin): 
    def changelist_view(self, request, *args, **kwargs): 
     from django.http import HttpResponseRedirect 
     if self.default_filters: 
      try: 
       test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO']) 
       if test and test[-1] and not test[-1].startswith('?'): 
        url = reverse('admin:%s_%s_changelist' % (self.opts.app_label, self.opts.module_name)) 
        filters = [] 
        for filter in self.default_filters: 
         key = filter.split('=')[0] 
         if not request.GET.has_key(key): 
          filters.append(filter) 
        if filters:       
         return HttpResponseRedirect("%s?%s" % (url, "&".join(filters))) 
      except: pass 
     return super(DefaultFilterMixIn, self).changelist_view(request, *args, **kwargs)    

Et puis il suffit de définir un default_filters sur votre ModelAdmin:

class YourModelAdmin(DefaultFilterMixIn): 
    .... 
    default_filters = ('snapshot__exact=0',) 
+0

pour moi (qui pourrait être différent parce que j'utilise django-grappelli) cela fonctionne MAIS seulement quand c'est 'snapshot = 0' et pas' snapshot__exact = 0' et aussi, pour une raison quelconque, les filtres ne fonctionnent plus et c'est parce que le javascript est broken (la console dit: "Uncaught TypeError: Object [object Object] n'a pas de méthode 'actions'") et encore une fois cela pourrait être à cause de grappelli. désolé pour la phrase en cours, lol. –

+0

a travaillé très bien pour moi avec django == 1.3.4 et grappelli == 2.3.9. principaux accessoires pour le mixin. –

+0

Merci pour cet extrait, mais il ne fonctionne pas avec Python 3 et Django 1.9.7. Faire taire les exceptions n'est pas une bonne idée, alors j'ai commenté cela. Ensuite, j'ai trouvé que self.opts.module_name devrait être self.opts.model_name à la place et "' request.GET.has_key (key) '": a été remplacé par "' key in request.GET' ": (code mis à jour trop long être accepté ici) –

1

Cela a fonctionné pour moi et évité d'avoir le problème « Tous » mentionné par h3.

5

J'ai résolu ce problème avec le support 'all'.

dans models.py:

STATUSES_CHOICE = (
    ('0', 'Active'), 
    ('1', 'Deactive'), 
    ('2', 'Suspended'), 
) 

class Client(models.Model): 
    ... 
    status = models.IntegerField(verbose_name=_('Status'), 
           default=0, 
           db_index=True) 

dans admin.py:

class StatusAdminFilter(SimpleListFilter): 
    title = _('Status') 
    parameter_name = 'status' 
    all_param_value = 'all' 

    def lookups(self, request, model_admin): 
     return STATUSES_CHOICE 

    def queryset(self, request, queryset): 
     status = self.value() 
     try: 
      return (queryset if status == self.all_param_value else 
        queryset.filter(status=int(status))) 
     except ValueError: 
      raise Http404 

    def choices(self, cl): 
     yield {'selected': self.value() == self.all_param_value, 
       'query_string': cl.get_query_string(
        {self.parameter_name: self.all_param_value}, 
        [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} 


class ClientAdmin(admin.ModelAdmin): 
    list_filter = (StatusAdminFilter,) 

    def changelist_view(self, request, extra_context=None): 
     if not request.GET.has_key('status'): 
      q = request.GET.copy() 
      q['status'] = '0' # default value for status 
      request.GET = q 
      request.META['QUERY_STRING'] = request.GET.urlencode() 
     return super(ClientAdmin, self).changelist_view(
      request, extra_context=extra_context) 
+0

Dieu merci. Je ne pouvais pas trouver un moyen de supprimer "Tous". Tout le monde a dit que vous l'avez laissé dans la fonction "recherche". En réalité, vous avez dû le laisser dans la fonction "choix" – MagicLAMP

5

solution à court et propre. Fonctionne bien avec l'option "Tous" lorsque vous cliquez sur Modifier la vue de la liste.

def changelist_view(self, request, extra_context=None): 
     if not request.META['QUERY_STRING'] and \ 
      not request.META.get('HTTP_REFERER', '').startswith(request.build_absolute_uri()): 
      return HttpResponseRedirect(request.path + "?status__exact=1") 
     return super(YourModelAdmin,self).changelist_view(request, extra_context=extra_context) 
1

Voici ma mise à jour pour le code de glic3rinu (voir le commentaire là-bas), qui fonctionne sur Python 3.4 et Django 1.9.7:

class DefaultFilterMixIn(admin.ModelAdmin): 
    def changelist_view(self, request, *args, **kwargs): 
     from django.http import HttpResponseRedirect 
     if self.default_filters: 
      #try: 
       test = request.META['HTTP_REFERER'].split(request.META['PATH_INFO']) 
       if test and test[-1] and not test[-1].startswith('?'): 
        url = reverse('admin:{}_{}_changelist'.format(self.opts.app_label, self.opts.model_name)) 
        filters = [] 
        for filter in self.default_filters: 
         key = filter.split('=')[0] 
         if not key in request.GET: 
          filters.append(filter) 
        if filters:      
         return HttpResponseRedirect("{}?{}".format(url, "&".join(filters))) 
      #except: pass 
     return super(DefaultFilterMixIn, self).changelist_view(request, *args, **kwargs)    
0

Voici ma tentative d'avoir un filtre par défaut défini dans admin (testé uniquement avec Django 1.11):

class ZeroCountListFilter(admin.SimpleListFilter): 
    title = _('include zero count') 
    parameter_name = 'count' 

    def choices(self, changelist): 
     yield { 
      'selected': self.value() is None or self.value() == 0, 
      'query_string': changelist.get_query_string({}, [self.parameter_name]), 
      'display': _('No'), 
     } 
     yield { 
      'selected': self.value() == '1', 
      'query_string': changelist.get_query_string({self.parameter_name: '1'}, []), 
      'display': _("Yes"), 
     } 

    def lookups(self, request, model_admin): 
     return (
      ('0', _('No')), 
      ('1', _('Yes')), 
     ) 

    def queryset(self, request, queryset): 
     if self.value() is None or self.value() == '0': 
      return queryset.exclude(count=0) 
     else: 
      return queryset 

L'astuce est de vérifier self.value() is None pour obtenir le comportement par défaut

Questions connexes