2011-09-03 8 views
3

J'ai une question - Est-ce que l'interface Django Admin peut être personnalisée de manière à ce qu'elle ne présente que les options de filtrage qui se produisent dans le sous-ensemble de données qui correspondent aux filtres actuellement sélectionnés?django admin filters cascading

que j'ai un db de trois objets:

a.Foo = "One" 
a.Bar = "Drink" 

b.Foo = "One" 
b.Bar = "Shot" 

c.Foo = "Two" 
c.Bar = "Shot" 

Et une interface d'administration de django avec des filtres sur 'Foo' et 'Bar'. Je veux le comportement suivant:

  • Si aucun filtre n'est choisi, 'Foo' liste "One", "Two"; 'Bar' affiche "Boire", "Shot"
  • Si le filtre 'Foo' est réglé sur "One", 'Bar' affiche à la fois "Drink" et "Shot"
  • Si le filtre 'Foo' est réglé sur " Deux "," Bar "liste uniquement" Shot "
  • Si le filtre 'Bar' est réglé sur" Shot ", 'Foo' liste" One "et" Two "
  • Si le filtre 'Bar' est réglé sur" Boire "," Foo "liste seulement" Un "

Cheers!


Pour être plus précis - après avoir lu quelques docs:

from django.contrib.admin import SimpleListFilter 

class SomeFilter(SimpleListFilter): 
    title = "Foo" 
    parameter_name="Some" 
    def lookups(self, request, model_admin): 
    qs = model_admin.queryset(request) 
    print qs.query 
    return (('Foo', 'Bar')) 
    def queryset(self, request, queryset): 
    if (self.value()): 
     return queryset.filter(Some=self.value()) 
    else: 
     return queryset 

Ce qu'il fait, cependant, est obtient le « queryset », car il aurait été sans d'autres filtres. Comment puis-je le passer à travers d'autres filtres?


Je pourrais théoriquement analyser la requête et filtrer manuellement - mais il doit sûrement y avoir un moyen de canaliser tous les filtres.

+0

Ajouté plus d'informations après quelques recherches - Je ne peux pas tout à fait comprendre comment obtenir le jeu de requête après que tous les autres filtres l'aient traversé. – qdot

Répondre

2

Ce type de filtrage dynamique ressemble vraiment à un facettage. Bien que vous puissiez atteindre ce résultat avec un jeu de requête standard, cela ne sera probablement pas optimal. Vous pouvez avoir plus de chance en utilisant un outil dédié, comme Solr.

Haystack has also a doc page on faceting.

+0

haystack ressemble vraiment à un bon endroit pour commencer à percer .. bon conseil! – qdot

1

au cas où quelqu'un a besoin d'une solution légère, ce que l'on fait un filtre pays qui est caché quand aucun continent est sélectionné dans le filtre et ne propose que les pays qui existent dans le continent sélectionné:

from django.utils.translation import ugettext_lazy as _ 
class ContinentCountryListFilter(admin.SimpleListFilter): 
    # Human-readable title which will be displayed in the 
    # right admin sidebar just above the filter options. 
    title = _('country') 

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

    def lookups(self, request, model_admin): 
     """ 
     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. 
     """ 

     continent = request.GET.get('country__continent__iso_code__exact', '') 

     if continent: 
      countries = models.Country.objects.filter(continent__iso_code__exact=continent) 
     else: 
      countries = models.Country.objects.none() 

     return countries.values_list('iso_code', 'name') 

    def queryset(self, request, queryset): 
     """ 
     Returns the filtered queryset based on the value 
     provided in the query string and retrievable via 
     `self.value()`. 
     """ 
     continent = request.GET.get('country__continent__iso_code__exact', '') 

     # only apply filter if continent is set and country exists in continent 
     if continent and models.Country.objects.filter(continent__iso_code__exact=continent, iso_code__exact=self.value()).count(): 
      return queryset.filter(country__iso_code__exact=self.value()) 

     return queryset 

puis appliquer avec:

list_filter = ('country__continent', ContinentCountryListFilter,)