You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Request传递给django-filters自定义Widget以保留筛选状态

如何将Request传递到Django Filter的自定义Widget中以保留筛选状态

我想创建一个类似Fiverr的筛选器(下拉选择搭配输入选项的组合),目前已完成Widget的创建,可选择选项并提交子输入值,但页面加载后值会丢失且无选项被选中。原因是单选框的值需要从request.GET中获取,但我无法将Request传递到Widget里——Filter类中可以拿到Request,但Widget中拿不到。

现有代码

自定义Widget代码

class PriceFilter(Widget):
    template_name = 'widgets/PriceFilter.html'

    def __init__(self, attrs=None, min=0, max=5000, *args, **kwargs):
        self.min = min
        self.max = max
        # print(self.request)
        print(kwargs)
        super(PriceFilter, self).__init__()  


    def get_context(self, name, value, attrs=None, *args, **kwargs):
        context = super().get_context(name, value, attrs)
        context['min'] = self.min
        context['max'] = self.max
        print(self.request)
        print(kwargs)
        return context

Widget模板代码

<div class="btn-group">
    <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuClickableInside"
        data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
        Clickable inside
    </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenuClickableInside">
        <div class="form-check">
            <input class="form-check-input" type="radio" name="{{widget.name}}__selector"
                id="{{widget.name}}__selector" #if request.GET.price__selector==1 then ceck this#>
            <label class="form-check-label" for="{{widget.name}}__selector">
                Default radio
            </label>
            <div class="input-filters">
                <input type="hidden" name="{{widget.name}}__lt" id="id_{{widget.name}}__lt"
                    value="{{widget.value|default_if_none:''}}">
            </div>
        </div>
    </ul>
</div>

Filter类代码

class ListFilter(django_filters.FilterSet):
    price = django_filters.NumberFilter(widget=PriceFilter())

    class Meta:
        model = MainModel
        fields = {
                'name':['contains'],'price':[]
            }

    def __init__(self, *args, **kwargs):
        print('kwgs')
        # print(args[0])
        self.request = kwargs.pop('request', None)
        super(ListFilter, self).__init__(*args, **kwargs)
        self.filters["price"].request = args[0]

解决方案

步骤1:在Filter初始化时给Widget传递Request

修改Filter的__init__方法,直接为目标Widget实例添加request属性:

class ListFilter(django_filters.FilterSet):
    price = django_filters.NumberFilter(widget=PriceFilter())

    class Meta:
        model = MainModel
        fields = {
                'name':['contains'],'price':[]
            }

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)
        super(ListFilter, self).__init__(*args, **kwargs)
        # 给price字段的Widget传递request
        if self.request:
            self.filters["price"].widget.request = self.request

步骤2:修改Widget将Request传入模板上下文

调整Widget的__init__和get_context方法,确保request能被传递到模板:

class PriceFilter(Widget):
    template_name = 'widgets/PriceFilter.html'

    def __init__(self, attrs=None, min=0, max=5000, *args, **kwargs):
        self.min = min
        self.max = max
        self.request = None  # 初始化request属性
        super().__init__(attrs)  # 正确传递attrs给父类

    def get_context(self, name, value, attrs=None):
        context = super().get_context(name, value, attrs)
        context['min'] = self.min
        context['max'] = self.max
        # 将request加入模板上下文
        if hasattr(self, 'request'):
            context['request'] = self.request
        return context

步骤3:修改模板实现选中状态判断

用Django模板语法替换伪代码,实现单选框的选中逻辑:

<div class="btn-group">
    <button class="btn btn-secondary dropdown-toggle" type="button" id="dropdownMenuClickableInside"
        data-bs-toggle="dropdown" data-bs-auto-close="outside" aria-expanded="false">
        Clickable inside
    </button>
    <ul class="dropdown-menu" aria-labelledby="dropdownMenuClickableInside">
        <div class="form-check">
            <input class="form-check-input" type="radio" name="{{widget.name}}__selector"
                id="{{widget.name}}__selector" {% if request.GET.price__selector == '1' %}checked{% endif %}>
            <label class="form-check-label" for="{{widget.name}}__selector">
                Default radio
            </label>
            <div class="input-filters">
                <input type="hidden" name="{{widget.name}}__lt" id="id_{{widget.name}}__lt"
                    value="{{request.GET.price__lt|default_if_none:''}}">
            </div>
        </div>
    </ul>
</div>

额外注意

确保在视图中初始化FilterSet时传入request参数:

filter = ListFilter(request.GET, queryset=MainModel.objects.all(), request=request)

内容的提问来源于stack exchange,提问作者El hosayn Ait Ali

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 17:43:12