django-filter:如何按字段A过滤但是将字段B显示为相应的过滤选项/文本?

时间:2017-06-30 20:57:20

标签: django django-filter

我有一个Django Post模型,其fk为Category模型,带有类别名称和类别slug。现在,我通过django-filterLinkWidget按类别过滤这些帖子。这很好,通过name="categories__name"开箱即用:

# models.py
class Category(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField(unique=True)

class Post(models.Model):
    categories = models.ManyToManyField(Category)
# filters.py
class PostFilter(django_filters.FilterSet):

    categories = django_filters.AllValuesFilter(
        name="categories__name",
        label="Categories",
        widget=LinkWidget(),
    )

    class Meta:
        model = Post
        fields = ['categories',]
# template.html

<h2>Filter</h2>
{% for choice in filter.form.categories %}
   {{ choice }}    
{% endfor %}

<h2>Posts</h2>
<ol>
{% for obj in filter.qs %}
    <li>{{ obj.title }}</li>
{% endfor %}

但是现在我想取消categories__name作为GET参数并使用categories__slug代替 - 但保持人类可读性categories__name作为LinkWidget中的链接文字} - 但我不知道如何实现这一点,任何提示?

一些渲染的html片段:

通过name=categories__slug过滤:

<ul id="id_categories">
    <li><a href="?categories=audio-and-video">audio-and-video</a></li>
    <li><a href="?categories=bits-bytes">bits-bytes</a></li>
    <li><a href="?categories=foo-and-bar">foo-and-bar</a></li>
</ul>

通过name=categories__name过滤:

<ul id="id_categories">
    <li><a href="?categories=Audio+and+Video">Audio and Video</a></li>
    <li><a href="?categories=Bits%2FBytes">Bits/Bytes</a></li>
    <li><a href="?categories=Foo+and+Bar">Foo and Bar</a></li>
</ul>

但我想要的是(伪代码):

<li><a href="?categories={{ category.slug }}">{{ category.name }}</a></li>

...并呈现:

<ul id="id_categories">
    <li><a href="?categories=audio-and-video">Audio and Video</a></li>
    <li><a href="?categories=bits-bytes">Bits/Bytes</a></li>
    <li><a href="?categories=foo-and-bar">Foo and Bar</a></li>
</ul>

也许在一个最小的,完整的django项目中查看这个问题会更容易,所以我做了一个:https://gitlab.com/tombreit/django-filter-demo

版本:

  • Python 3.5.3
  • Django(1.10.7)
  • django-filter(1.0.4)

1 个答案:

答案 0 :(得分:0)

试试这个解决方案:

class CustomAllValuesFilter(django_filters.ChoiceFilter):
    @property
    def field(self):
        qs = self.model._default_manager.distinct()
        qs = qs.order_by(self.name).values_list(self.name, self.extra['choice_name'])
        del self.extra['choice_name']
        self.extra['choices'] = list(qs)
        return super(CustomAllValuesFilter, self).field


class PostFilter(django_filters.FilterSet):
    categories = CustomAllValuesFilter(
        name="categories__slug",
        label="Categories",
        widget=LinkWidget(),
        choice_name="categories__name"
    )

    class Meta:
        model = Post
        fields = ['categories',]