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

如何过滤以字典而非模型为数据源的Django Table2表格

问题原因

你触发的报错是因为django-filter的FilterSet默认是为Django ORM的QuerySet设计的,你没有在FilterSet的Meta中绑定对应的Model,也没有适配列表类型的数据源,初始化时FilterSet会尝试读取Model的默认管理器生成默认QuerySet,自然就抛出了NoneType相关错误。
另外你之前修改table.data.data无效,是因为RequestConfig.configure方法会重置表格的数据源配置,在配置之后修改数据源会被覆盖,正确的逻辑应该是先过滤数据,再用过滤后的数据实例化表格。

解决方案

我们可以自定义FilterSet的过滤逻辑,适配字典列表类型的数据源,步骤如下:

1. 改造FilterSet

重写过滤方法,把默认的ORM查询逻辑改成对字典列表的逐行匹配:

# filters.py
import django_filters

class RawInterfaceFilter(django_filters.FilterSet):
    hostname = django_filters.CharFilter(lookup_expr='icontains', method='filter_dict_list')
    interface = django_filters.CharFilter(lookup_expr='icontains', method='filter_dict_list')
    status = django_filters.CharFilter(lookup_expr='icontains', method='filter_dict_list')
    speed = django_filters.CharFilter(lookup_expr='icontains', method='filter_dict_list')

    class Meta:
        # 不需要指定model,我们自定义过滤逻辑
        fields = ['hostname', 'interface', 'speed', 'status']

    def filter_dict_list(self, queryset, name, value):
        # 这里的queryset就是我们传入的字典列表
        if not value:
            return queryset
        
        # 字段和字典取值路径的映射,和Table里的Accessor规则保持一致
        field_path_map = {
            'hostname': lambda item: item['system']['hostname'],
            'interface': lambda item: item['interfaces']['name'],
            'status': lambda item: item['interfaces']['protocol'],
            'speed': lambda item: item['interfaces']['speed'],
        }
        # 模拟icontains效果,不区分大小写匹配
        value = value.lower()
        return [
            item for item in queryset
            if value in field_path_map[name](item).lower()
        ]

2. 修改视图逻辑

先处理原始数据,再做过滤,最后用过滤后的数据实例化表格:

# views.py
class RawInterfaceList(View):
    """Displays all the interfaces from all devices in table form"""

    def get(self, request):
        # 第一步:生成原始的字典列表数据
        all_configs = []
        for device in Device.objects.all():
            config = device.deviceconfiguration.config
            input_data = {
                'system': config['system'],
                'interfaces': config['interfaces']
            }
            all_configs.append(proccess(input_data)) # 自定义处理逻辑
        
        # 第二步:对数据做过滤
        # 把字典列表作为queryset传入FilterSet,同时传入GET参数
        filter_obj = RawInterfaceFilter(request.GET, queryset=all_configs)
        filtered_data = filter_obj.qs

        # 第三步:用过滤后的数据实例化表格(注意之前你写的all_configs[0]是错的,要传完整列表)
        table = RawConfigTable(filtered_data)
        RequestConfig(request).configure(table)

        return render(request, "plugin/raw_interfaces_list.html", {
            "table": table,
            "filter": filter_obj
        })

3. 模板使用

在模板中正常渲染过滤表单即可,表单用GET方法提交到当前页面:

<!-- 过滤表单示例 -->
<form method="get">
    {{ filter.form.as_p }}
    <button type="submit">过滤</button>
</form>

<!-- 渲染表格 -->
{% render_table table %}

扩展说明

如果需要更复杂的过滤规则(比如数值范围、多选匹配等),只需要修改filter_dict_list里的匹配逻辑即可,不需要依赖ORM模型。


内容的提问来源于stack exchange,提问作者Jasper

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.18 00:54:00