Feed the current filter to another custom SimpleListFilter in Django

I am trying to make hints about changing one filter in response to the current selection made in another filter. I am quite lost on how to get the currently selected AttributeCategoryFilter value passed to AttributeFilter. I am using Django 1.4-dev. Trying to find out if I should use SpecialFieldListFilter for this. It looks like these features are so young they don't have (m) any examples floating around in the wild.

    class AttributeCategoryFilter(SimpleListFilter):
        title = _('Attribute Category')
        parameter_name = 'attribute_category'
        def lookups(self, request, model_admin):
            attributes = Attribute.objects.filter(parent_attribute=None)
            prompts = []
            for attribute in attributes:
                prompts.append((attribute.title, _(str(attribute.title))))
            return prompts
        def queryset(self, request, queryset):
            if self.value():
                return queryset.filter(attribute__category=self.value())
            else:
                return queryset


    class AttributeFilter(SimpleListFilter):
        title = _('Attribute Title')
        parameter_name = 'attribute_title'
        def lookups(self, request, model_admin):
            desired_category =  # Needs to be a reference to the selected value in the AttributeCategoryFilter above
            attributes = Attribute.objects.filter(category=desired_category).exclude(parent_attribute=None)
            prompts = []
            for attribute in attributes:
                prompts.append((attribute.title, _(str(attribute.title))))
            return prompts
        def queryset(self, request, queryset):
            if self.value():
                return queryset.filter(attribute__title=self.value())
            else:
                return queryset


    class ValueAdmin(admin.ModelAdmin):
        list_display = ('package', 'attribute', 'presence', 'text', 'modified', 'created')
        list_filter = ('package', AttributeCategoryFilter, AttributeFilter, 'presence', 
            'attribute__admin_approved', 'attribute__dtype', 'modified')
        search_fields = ('package', 'attribute', 'text')
        list_display_links = ('package', )
        list_editable = ('presence', 'text')
        list_per_page = 20000
    admin.site.register(Value, ValueAdmin)   

      

+3


source to share


2 answers


Here's what worked for me ... "TypeListFilter" only shows after using the "Category" filter, and then displays all entries that are "subTypeOf" of the selected category. Hacking the "special case" further ensures that the filter disappears when the user selects a different category. The "_class" parameter adds additional flexibility. I am using the same filter with different but related type classes and just have to override this setting. Just replace it with the admin.Model class you want to filter out.



class TypeListFilter( admin.SimpleListFilter):
    """
    Provide filter for DnaComponentType (the actual "second level" type).

    This filter has one cosmetic problem, which is that it setting is not
    automatically deleted if the category filter is changed. I tried but the
    request and queryset are all immutable. Instead, the queryset method is 
    checking for any missmatch between category and filter name and filtering
    is ignored if the category name doesn't match the current subType name.
    """
    title = 'Type'
    parameter_name = 'type'

    _class = None

    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.
        """
        if not u'category' in request.GET:
            return ()

        category_name = request.GET[u'category']
        types = self._class.objects.filter(subTypeOf__name=category_name)
        return ( (t.name, t.name) for t in types )

    def queryset(self, request, queryset):
        """
        Returns the filtered queryset based on the value
        provided in the query string and retrievable via
        `self.value()`.
        """
        if not u'category' in request.GET:
            return queryset

        category = request.GET[u'category']
        subtypes = self._class.objects.filter(subTypeOf__name=category)

        r = queryset.filter(componentType__subTypeOf__name=category)

        if not self.value():
            return r

        ## special case: missmatch between subtype and category
        ## which happens after switching the category
        if len(subtypes.filter(name=self.value())) == 0:
            return r

        return r.filter(componentType__name=self.value())

      

+2


source


Found your question as I was looking for something else.

Here's what I did to only show players who had characters in the selected game:

def lookups(self, request, model_admin):
    game_id = request.GET.get('game', None)
    players = Player.objects.all()
    if game_id:
        players = players.filter(character__game_id=game_id)
    return [(p.id, p.__unicode__()) for p in players]

      



It looks like this is what dan-klasson suggested.

Hint: Placing identifiers in request parameters is generally considered no-no for security reasons.

+1


source







All Articles