在Django中使用下拉列表过滤ListView的最佳方法

时间:2017-09-29 15:07:16

标签: django listview filter

我尝试使用下拉表格过滤基于用户的ListView。

models.py

class Post(models.Model):
    ...
    author = models.ForeignKey('auth.User', verbose_name="Post Author")

views.py

class PostList(ListView):
    model = Post
    context_object_name = 'posts'

    def get_queryset(self):
        result = super(PostList, self).get_queryset()

        author_filter = self.request.GET.get('author')
        if author_filter:
            result = Post.objects.filter(Q(author__icontains=author_filter))
        return result

post_list.html

<form action="" method="get">
          <select name="author" onchange="this.form.submit();">
            <option selected="selected" disabled>Select an author</option>
            {% all_author as authors %}
            {% for author in authors %}
            <option value="{{ author }}">{{ author }}</option>
            {% endfor %}
          </select>
        </form>

我使用自定义模板标记来呈现all_authors,这很好用。选择作者时,在网址中我可以看到传递的内容(/?author = xxx),但列表未被过滤。

修改

根据andi的建议,我使用django过滤器以这种方式工作。但由于某些原因,不考虑filters.py中的fields = ['field_name',],因此我在模板中单独选择字段。

views.py

class PostList(FilterView):
    model = Post
    filter_class = PostFilter
    context_object_name = 'posts'
    paginate_by = 50
    template_name = 'directory/post_list.html'

filters.py

class PostFilter(django_filters.FilterSet):

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

post_list.html

<form action="" method="get">
            {{ filter.form.author }}
            <input type="submit" />
        </form>

编辑2

我发现为什么所选字段未正确传递,需要在视图中使用filterset_class =而不是filter_class =

2 个答案:

答案 0 :(得分:6)

哦,这真的是老式的,容易出错和耗时的做事方式。

请试试django-filter图书馆。并以最少的努力创建工作精细的过滤器!这样可以在保持干净代码的同时创建非常强大的过滤策略。

https://django-filter.readthedocs.io/en/latest/guide/usage.html#

低于快速草案:

过滤器:

import django_filters

class PostFilter(django_filters.FilterSet):
    class Meta:
        model = Post
        fields = ['author']

观点:

from django_filters.views import FilterView
from somwhere.in.your.project.filtersets import PostFilter

class PostList(FilterView):
    model = Post
    context_object_name = 'posts'
    filter_class = PostFilter
模板中的

{% extends "base.html" %}

{% block content %}
    <form action="" method="get">
        {{ filter.form.as_p }}
        <input type="submit" />
    </form>
    {% for obj in filter.qs %}
        {{ obj.name }} - ${{ obj.price }}<br />
    {% endfor %}
{% endblock %}

答案 1 :(得分:0)

在您的表单中,尝试更改此内容:

<option value="{{ author }}">{{ author }}</option>

到此:

<option value="{{ author.pk }}">{{ author }}</option>

然后,在您看来:

if author_filter:
    result = Post.objects.filter(author_id=int(auth_filter))