问题
I am trying to make the prompts of one filter change in response to the current selection made in another filter. I am pretty lost as to how to get the currently selected value of the AttributeCategoryFilter passed into the AttributeFilter. I am using Django 1.4-dev. Trying to figure out if I should be using RelatedFieldListFilter for this purpose. It looks like these features are so young as to not have (m)any examples floating around in the wild yet.
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)
回答1:
Here is what worked for me... The "TypeListFilter" is only visible once the "Category" filter is used and then displays all the entries that are a "subTypeOf" the selected category. The "special case" hack further down ensures that the filter disappears when the user selects another Category. The "_class" parameter adds some extra flexibility. I am using the same filter with different but related Type classes and just have to override this one parameter. Just replace it by the admin.Model class that you want to filter.
class TypeListFilter( admin.SimpleListFilter):
"""
Provide filter for DnaComponentType (the actual "second level" type).
This filter has one cosmetic problem, which is that it's 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:
Found your question as I was looking for something else.
Here's what I did to only show players that had characters in a 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]
Looks like this is what dan-klasson suggested too.
Hint: Putting ids into query parameters is generally considered a no-no for security reasons.
来源:https://stackoverflow.com/questions/9707002/feeding-a-current-filter-selection-to-another-custom-simplelistfilter-in-django