如何过滤以字典而非模型为数据源的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
相关产品推荐
相关产品推荐

