django admin过滤级联

时间:2011-09-03 22:04:43

标签: django database django-admin

我有一个问题 - 可以通过这种方式自定义Django Admin界面,它只显示与当前所选过滤器匹配的数据子集中出现的那些过滤器选项吗?

假设我有三个对象的数据库:

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

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

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

还有一个django管理界面,在'Foo'和'Bar'上有过滤器。我想要以下行为:

  • 如果没有选择过滤器,'Foo'列出“One”,“Two”; 'Bar'列出“Drink”,“Shot”
  • 如果'Foo'过滤器设置为“One”,则“Bar”列出“Drink”和“Shot”
  • 如果'Foo'过滤器设置为“Two”,则“Bar”仅列出“Shot”
  • 如果'Bar'过滤器设置为“Shot”,'Foo'列出“One”和“Two”
  • 如果'Bar'过滤器设置为“Drink”,则'Foo'仅列出“One”

干杯!


更具体 - 阅读一些文档之后:

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
然而,它的作用是获取'queryset',因为它没有其他过滤器。如何通过其他过滤器传递它?


理论上我可以解析请求并手动过滤 - 但肯定需要一种方法来管道所有过滤器。

2 个答案:

答案 0 :(得分:2)

这种动态过滤看起来很像分面。虽然您可以使用标准查询集来实现此结果,但这可能不是最佳的。您可能有更多机会使用专用工具,例如Solr。

Haystack has also a doc page on faceting

答案 1 :(得分:1)

如果有人需要轻量级解决方案,那么当过滤器中未选择任何大陆时,此过滤器会隐藏国家过滤器,并且仅提供所选大陆中存在的那些国家/地区:

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

然后申请:

list_filter = ('country__continent', ContinentCountryListFilter, )