Django-filter: (2.0) FilterView 总是为未绑定的 FilterSet 返回空的 QuerySet。

创建于 2018-06-29  ·  19评论  ·  资料来源: carltongibson/django-filter

我有一个视图AccountList ,它试图呈现一个 django_table2 表。 视图的源代码:

class AccountList(SingleTableMixin, FilterView):
    model = Account
    table_class = AccountTable
    template_name = 'accounts/account_list.html'
    context_table_name = 'object_list'
    ordering = ['vps']

    filterset_class = AccountFilter

此视图当前正在使用此过滤器集(来自 django_filters):

import django_filters
from accounts.models import Account

class AccountFilter(django_filters.FilterSet):
    class Meta:
        model = Account
        fields = ['is_suspended', 'is_abandoned']

    is_suspended = django_filters.BooleanFilter(name='is_suspended', initial='False')
    is_abandoned = django_filters.BooleanFilter(name='is_abandoned', initial='False')

    def __init__(self, data=None, *args, **kwargs):
        # if filterset is bound, use initial values as defaults
        if data is not None:
            # get a mutable copy of the QueryDict
            data = data.copy()

            for name, f in self.base_filters.items():
                initial = f.extra.get('initial')

                # filter param is either missing or empty, use initial as default
                if not data.get(name) and initial:
                    data[name] = initial

        super().__init__(data, *args, **kwargs)

使用这个模板:

{% if filter %}
    <form action="" method="get" class="form form-inline">
        {{ filter.form.as_p }}
        <input type="submit" />
    </form>
{% endif %}

{% render_table object_list %}

{% endblock %}

这是我的 urls.py

path('', login_required(AccountList.as_view())),

当我访问我的页面127.0.0.1:8000 ,我看到未设置过滤器:
enter image description here

但是,如果我执行127.0.0.1:8000?page=1 ,我会看到过滤器已正确初始化:

enter image description here

当我没有将 page=1 附加到我的 url 时,是什么导致我的过滤器没有默认值?

最有用的评论

是的 - 开始了 PR 但不得不搁置我的开源工作。 我应该能够很快从我离开的地方开始。

所有19条评论

尝试使用实际的False布尔值而不是字符串值'False'

因此,当我尝试以下操作时:

is_suspended = django_filters.BooleanFilter(name='is_suspended', initial=False)
is_abandoned = django_filters.BooleanFilter(name='is_abandoned', initial=False)

这就是过滤器在127.0.0.1:8000/上的呈现方式

image

即使过滤器使用正确的值呈现,过滤器也不起作用,因为我仍然可以看到被暂停或放弃的帐户。

此外,当我通过按下底部的2按钮访问第 2 页时,我会到达http://127.0.0.1:8000/?page=2并将过滤器重置为Unknown

image

你看出什么原因了吗?

对不起 - 没有什么明显的想到。

对于第一个问题,我建议查看生成的 SQL 查询。 确保实际应用了suspendedabandoned过滤器。
对于第二个问题,我会检查传入的数据。 更改页面时,可能会向suspendedabandoned过滤器提供无效值。

我插入了一些打印语句,发现以下内容:

def __init__(self, data=None, *args, **kwargs):
    if data is not None:        # 1
        data = data.copy()

        for name, f in self.base_filters.items():
            initial = f.extra.get('initial')   

            # filter param is either missing or empty, use initial as default
            if not data.get(name) and initial:
                data[name] = initial

    super(BaseFilterSet, self).__init__(data, *args, **kwargs)

所以看起来dataNone 。 你会知道为什么我的基于类的视图没有将data传递给AccountFilter吗?

嗯。 data参数应始终由FilterView

https://github.com/carltongibson/django-filter/blob/b1f1c6592ef64a2172ec39040607a9c0b0714140/django_filters/views.py#L39 -L46

第一页和第二页的data空的吗?

这不能按原样解决。 关闭待处理的足够信息以识别问题。

升级到 2.0 后同样的问题。 URL 中应存在默认页面或空过滤器以获取结果。 这至少在某处记录了吗?

仍然需要更多信息才能重现...

page ? 这不是与您的分页有关,而不是与 Django 过滤器有关吗?

具体需要什么信息? 升级到 2.0 会导致所描述的行为。 降级到 1.1.0 使一切恢复正常。 我尝试将视图和过滤器集简化为尽可能简约,行为仍然存在,因此看起来这应该很容易重现。

@moorchegue ,演示该问题的最小示例测试用例或测试项目会有所帮助。

看起来问题出在提供分页逻辑的任何内容上。 是的,可能与新版本存在一些不兼容,但在其他包中调试问题超出了范围。 您需要在 Django 过滤器中演示一个错误,以便我们可以在这里做任何事情。

好的,所以这里的问题是作为#788 的一部分引入的is_valid()方法。

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/django_filters/filterset.py#L202 -L206

dataNone时,它会自动返回False None

在视图中,我们将object_listqs.none()

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/django_filters/views.py#L80 -L83

因此观察到的行为。

对此的测试不会失败,因为测试模板使用的是filter.qs而不是object_list

https://github.com/carltongibson/django-filter/blob/1dde11c70eedeac32f6de92c426deb289e1aebd8/tests/templates/tests/book_filter.html#L3 -L5

直接的解决方法是在您的过滤器集上设置strict = False 。 这导致实际无效的过滤器参数将导致部分过滤而不是显示空结果,但它现在应该是可行的。 (当然最好是覆盖视图get逻辑......)

我们会思考并改进对未绑定案例的处理。

嗯。 这里的主要缺陷是 View 的object_list和 FilterSet 的.qs之间的差异。 将严格行为移回FilterSet.qs可以解决这个问题。

此外,DRF 后端没有严格/非严格处理。

我会解决这个问题。

@rpkilby这个问题有什么进展吗?

是的 - 开始了 PR 但不得不搁置我的开源工作。 我应该能够很快从我离开的地方开始。

请注意,解决方法应该是在您的FilterMixin后代上设置strict = False (可能是View

在无界形式的情况下,您不能更改条件以返回 qs 吗?

例如

-        if self.filterset.is_valid() or not self.get_strict():
+        if not self.filterset.is_bound or self.filterset.is_valid() or not self.get_strict():

https://github.com/carltongibson/django-filter/pull/1007

谢谢。

此页面是否有帮助?
0 / 5 - 0 等级