django admin 过滤器级联

发布于 2024-12-02 17:16:46 字数 1124 浏览 0 评论 0原文

我有一个问题 - Django 管理界面是否可以以这样的方式进行自定义,使其仅显示与当前所选过滤器匹配的数据子集中出现的过滤器选项?

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

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

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

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

以及一个带有“Foo”和“Bar”过滤器的 django 管理界面。我想要以下行为:

  • 如果没有选择过滤器,“Foo”列出“One”、“Two”; “Bar”列出“Drink”、“Shot”
  • 如果“Foo”过滤器设置为“One”,“Bar”会列出“Drink”和“Shot”
  • 如果“Foo”过滤器设置为“Two”,“Bar”会 列出“Drink”和“Shot”仅列出“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

然而,它的作用是获取“查询集”,就像没有其他过滤器一样。我怎样才能让它通过其他过滤器?


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

I've got a question - can Django Admin interface be customized in such a way, that it presents only those filter options that occur in the subset of data matching currently selected filters?

Say I have a db of three objects:

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

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

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

And a django admin interface with filters on 'Foo' and 'Bar'. I want the following behavior:

  • If no filters are chosen, 'Foo' lists "One","Two"; 'Bar' lists "Drink", "Shot"
  • If 'Foo' filter is set to "One", 'Bar' lists both "Drink" and "Shot"
  • If 'Foo' filter is set to "Two", 'Bar' lists only "Shot"
  • If 'Bar' filter is set to "Shot", 'Foo' lists both "One" and "Two"
  • If 'Bar' filter is set to "Drink", 'Foo' lists only "One"

Cheers!


To be more specific - after reading some 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

What it does, however, is gets the 'queryset' as it would've been without other filters. How can I pass it through other filters?


I could theoretically parse the request and filter manually - but there surely needs to be a way to pipe all filters.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

鱼窥荷 2024-12-09 17:16:46

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

Haystack 还有一个有关分面的文档页面

This kind of dynamic filtering really looks like faceting. While you may be able to achieve this result with a standard queryset, this will probably not be optimal. You may have more chance using a dedicated tool, like Solr.

Haystack has also a doc page on faceting.

堇年纸鸢 2024-12-09 17:16:46

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

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, )

in case anyone needs a lightweight solution, this one does a Country filter that is hidden when no Continent is selected in the filter and only offers those countries that exist in the selected Continent:

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

and then apply with:

list_filter = ('country__continent', ContinentCountryListFilter, )
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文