如何在 Django 过滤器中将 queryset 或 kwarg 传递给 RangeFilter 类

how to pass queryset or kwarg to RangeFilter class in Django filters

提问人:Michael Romanov 提问时间:10/25/2023 更新时间:10/29/2023 访问量:61

问:

我正在开发一个 Django 驱动的网站,该网站使用 django 过滤器,特别是 RangeFilter 来显示房地产的价格,并将其可视化为搜索表单上的滑块。

我的查询集最初在 PropertyListView 中形成为具有特定状态(销售或租赁)的对象列表,然后将其传递给筛选器 PropertyFilter。

PropertyFilter 使用其他几个类来构造相应的小部件,例如价格的滑块:

class PropertyFilter(FilterSet):
    price = PriceFilter()
    ...


class PriceFilter(RangeFilter):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        values = [p.price for p in Property.objects.all()]
        min_value = min(values)
        max_value = max(values)
        self.extra['widget'] = CustomRangeWidget(attrs={'label':_('Price, €'),'data-range_min':min_value,'data-range_max':max_value})

问题在于 PriceFilter 不“知道”查询集中有哪些对象,而是从完整的对象列表中获取价格通道。这导致了尴尬的滑块,其直径太宽,从 600 到 300,000 欧元,这无关紧要。

我想让 PriceFilter 从查询集中获取价格。怎么可能做到呢?我尝试直接在此过滤器中使用查询集,将查询集传递到其中,或将状态作为 kwarg 参数传递,但每次我都遇到错误。

请帮帮我,我被困住了。

django django-queryset django-filter

评论


答:

1赞 Kiarash Gh 10/25/2023 #1

您可以修改该类以接受 QuerySet,并使用它来确定价格范围PriceFilter

class PriceFilter(RangeFilter):
    def __init__(self, queryset=None, *args, **kwargs):
        super().__init__(*args, **kwargs)
        if queryset is not None:
            values = [p.price for p in queryset]
            min_value = min(values) if values else 0
            max_value = max(values) if values else 0
            self.extra['widget'] = CustomRangeWidget(attrs={'label': _('Price, €'), 'data-range_min': min_value, 'data-range_max': max_value})
        else:
            self.extra['widget'] = CustomRangeWidget(attrs={'label': _('Price, €'), 'data-range_min': 0, 'data-range_max': 0})

然后,将查询集从 your 传递给 ,然后传递给 :PropertyListViewPropertyFilterPriceFilter

class PropertyFilter(FilterSet):
    price = PriceFilter(queryset=Property.objects.none()) # initialize with an empty queryset
    def __init__(self, data=None, queryset=None, *args, **kwargs):
        if queryset is not None:
            self.price = PriceFilter(queryset=queryset, *args, **kwargs)
        super().__init__(data, queryset, *args, **kwargs)
    # other filters

    class Meta:
        model = Property
        fields = ['price', ...]

现在,您可以在 QuerySet 中将查询集传递给:PropertyListViewPropertyFilter

class PropertyListView(ListView):
    model = Property

    def get_queryset(self):
        queryset = Property.objects.filter(status='your_status_goes_here')
        return queryset

    def get_context_data(self):
        context = super().get_context_data(**kwargs)
        property_filter = PropertyFilter(data=self.request.GET, queryset=self.get_queryset())
        context['filter'] = property_filter
        return context

这样,将仅考虑筛选的查询集中的价格,确保滑块反映适当的价格范围。PriceFilter

我希望这对你有所帮助。

评论

0赞 Michael Romanov 10/25/2023
谢谢你,Kiarash!我以为我已经尝试过这种方法,但我可能会做错什么。现在我会再试一次,完全按照你的计划,并报告它是否有效。
0赞 Michael Romanov 10/25/2023
你接近工作!PriceFilter 现在从 PropertyFilter 获取查询集。但是现在我需要 PropertyFilter 从 PropertyListView 获取查询集,而不是生成它。你能告诉我怎么做吗?我正在尝试,但仍然收到错误(目前PropertyFilter.__init__()为参数“queryset”提供了多个值)。
0赞 Michael Romanov 10/26/2023
根据逻辑,PropertyFiltes 应从 PropertyListView 获取查询集。但是我不知道如何访问它。当我编写 price = PriceFilter(queryset=self.kwargs['queryset']) 时,我收到错误“name 'self' is not defined”。请帮忙!
1赞 Kiarash Gh 10/27/2023
为此,您应该修改类以接受 from 并将其传递给类PropertyFilterquerysetPropertyListViewPriceFilter
1赞 Kiarash Gh 10/27/2023
我已经编辑了答案,希望这对:)有所帮助