news 2026/6/18 21:35:11

动态构建django-filter FilterSet

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
动态构建django-filter FilterSet

一个动态构建FilterSet的通用方法,可以用在api_view等比较灵活的场景当中

# utils/dynamic_filter.py from typing import Type, Union from django.db.models import QuerySet from django_filters import rest_framework as filters from django.db import models from django.db.models import Model from functools import lru_cache def get_filter_config(model_field, field_name): """ 根据字段类型返回对应的过滤器配置 规则: - 字符类型 → icontains(模糊搜索) - 外键/一对一 → 精确匹配 - 数字类型 → 精确匹配 - 布尔类型 → 精确匹配 - 日期时间 → 支持范围查询 - 多对多 → 包含查询 - UUID → 精确匹配 """ field_type = type(model_field) if field_type in [models.CharField, models.TextField, models.EmailField, models.URLField, models.SlugField]: # 主键、外键和一对一用精确匹配 if model_field.primary_key or isinstance(model_field, (models.ForeignKey, models.OneToOneField)): if isinstance(model_field, (models.ForeignKey, models.OneToOneField)): return filters.ModelChoiceFilter( field_name=field_name, queryset=model_field.related_model.objects.all() ) # 主键使用精确匹配 return filters.CharFilter(field_name=field_name, lookup_expr='exact') return filters.CharFilter(field_name=field_name, lookup_expr='icontains') elif field_type in [models.IntegerField, models.FloatField, models.DecimalField, models.PositiveIntegerField, models.SmallIntegerField, models.BigIntegerField]: return filters.NumberFilter(field_name=field_name) elif field_type == models.BooleanField: return filters.BooleanFilter(field_name=field_name) elif field_type in [models.DateTimeField, models.DateField]: return filters.DateTimeFilter(field_name=field_name) elif field_type == models.ForeignKey: return filters.CharFilter(field_name=field_name, lookup_expr='exact') # 多对多 elif field_type == models.ManyToManyField: return filters.ModelMultipleChoiceFilter( field_name=field_name, queryset=model_field.related_model.objects.all(), ) # UUID elif field_type == models.UUIDField: return filters.UUIDFilter(field_name=field_name) # 默认 else: return filters.CharFilter(field_name=field_name) @lru_cache(maxsize=128) def create_dynamic_filterset(model, filter_fields=(), exclude_fields=(), search_fields=(), search_param='search', ordering_fields=(), ordering_param='order_by'): """ 根据模型和字段列表动态创建 FilterSet(支持过滤 + 排序 + 搜索) Args: model: Django模型类 filter_fields: 需要过滤的字段列表,None表示所有字段 exclude_fields: 排除的字段列表 ordering_fields: 允许排序的字段列表,None表示所有字段 ordering_param: 前端传递排序参数的key,默认 'ordering' search_fields: 允许搜索的字段列表 search_param: 前端传递搜索参数的key,默认 'search' Returns: FilterSet: 动态生成的FilterSet类 """ filter_fields = list(filter_fields) if filter_fields else None exclude_fields = list(exclude_fields) if exclude_fields else None search_fields = list(search_fields) if search_fields else None ordering_fields = list(ordering_fields) if ordering_fields else None if filter_fields is None: filter_fields = [ f.name for f in model._meta.get_fields() if f.concrete and not f.auto_created ] if exclude_fields: filter_fields = [f for f in filter_fields if f not in exclude_fields] # 构建过滤器字典 filters_dict = {} for field_name in filter_fields: try: model_field = model._meta.get_field(field_name) filter_config = get_filter_config(model_field, field_name) if filter_config: filters_dict[field_name] = filter_config except models.FieldDoesNotExist: continue # 确定排序字段 if ordering_fields is None: ordering_fields = [] if ordering_fields: filters_dict[ordering_param] = filters.CharFilter( field_name='ordering', method='filter_ordering', label='排序' ) # 确定搜索字段 手动指定 # if search_fields is None: # # 默认搜索所有字符类型字段(排除外键) # search_fields = [ # f.name for f in model._meta.get_fields() # if f.concrete and not f.auto_created # and isinstance(f, (models.CharField, models.TextField, # models.EmailField, models.URLField, models.SlugField)) # ] # # 如果没有字符字段,添加主键作为搜索字段 # if not search_fields: # search_fields = ['id'] # 添加搜索过滤器 search_fields_list = [] if search_fields: filters_dict[search_param] = filters.CharFilter( field_name='search', method='filter_search', label='搜索' ) search_fields_list = search_fields # 创建 Meta 类 meta_class = type( 'Meta', (), # 父类元组 { 'model': model, 'fields': list(filters_dict.keys()) } ) # 创建 FilterSet 类 class_attrs = filters_dict.copy() class_attrs['Meta'] = meta_class def filter_ordering(self, queryset, name, value): """自定义排序方法 """ if not value: return queryset primary_key = model._meta.pk.name order_fields = [] for field in value.split(','): field = field.strip() if not field: continue if field.startswith('-'): order_field = field[1:] is_desc = True else: order_field = field is_desc = False if order_field in ordering_fields: if is_desc: order_fields.append(f'-{order_field}') else: order_fields.append(order_field) if order_fields: return queryset.order_by(*order_fields) else: return queryset.order_by(f'-{primary_key}') class_attrs['filter_ordering'] = filter_ordering class_attrs['_ordering_fields'] = ordering_fields class_attrs['_ordering_param'] = ordering_param # 添加搜索方法 def filter_search(self, queryset, name, value): """自定义搜索方法""" if not value: return queryset # 构建 OR 查询 from django.db.models import Q q_objects = Q() for field_name in search_fields_list: # 支持跨表搜索(双下划线) if '__' in field_name: q_objects |= Q(**{f'{field_name}__icontains': value}) else: # 检查字段是否存在 try: model._meta.get_field(field_name) q_objects |= Q(**{f'{field_name}__icontains': value}) except models.FieldDoesNotExist: # 忽略不存在的字段 continue return queryset.filter(q_objects) class_attrs['filter_search'] = filter_search class_attrs['_search_fields'] = search_fields_list class_attrs['_search_param'] = search_param # 创建类 filter_class = type( f'{model.__name__}DynamicFilter', (filters.FilterSet,), class_attrs ) return filter_class def build_query(request, model: Type[Model], queryset: QuerySet = None, filter_fields: Union[list, tuple] = (), exclude_fields: Union[list, tuple] = (), search_fields: Union[list, tuple] = (), search_param='search', ordering_fields: Union[list, tuple] = (), ordering_param='order_by'): """ 过滤和排序queryset 传入queryset从queryset中查,否则从model中查 filter_fields: 过滤字段,动态构建过滤器 search_fields: 模糊搜索字段 前端需传参 ?search=... ordering_fields: 排序字段 ordering_param:排序关键字 """ FilterClass = create_dynamic_filterset(model, tuple(filter_fields), tuple(exclude_fields), tuple(search_fields), search_param, tuple(ordering_fields), ordering_param) queryset = model.objects.all() if not queryset else queryset filterset = FilterClass(data=request.query_params, queryset=queryset, request=request) if not filterset.is_valid(): return None return filterset.qs
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/18 21:29:28

嵌入式PowerPC MPC801指令时序优化:从流水线原理到性能调优实践

1. 指令执行时序:性能优化的底层逻辑在嵌入式系统开发,尤其是对实时性要求苛刻的领域,理解处理器内核如何执行每一条指令,其重要性不亚于掌握一门编程语言。这不仅仅是理论,而是直接关系到你的代码能否在有限的硬件资源…

作者头像 李华
网站建设 2026/6/18 21:23:09

彻底清理Windows Phone遗留文件夹wpsystem,释放C盘空间

1. 项目概述:被忽视的“wpsystem”文件夹如果你在Windows电脑的C盘根目录下,或者某个移动存储设备的根目录里,看到一个名为“wpsystem”的文件夹,并且它占用了不小的空间,你的第一反应是什么?是病毒&#x…

作者头像 李华
网站建设 2026/6/18 21:20:51

MPC8240 PowerPC SPR深度解析:从MMU加速到硬件调试实战

1. 项目概述与核心价值如果你正在开发基于PowerPC架构的嵌入式系统,尤其是使用像MPC8240这样集成了603e核心的处理器,那么你迟早会与一组名为“特殊功能寄存器”的硬件接口打交道。这些寄存器,通常缩写为SPR,是软件与处理器核心最…

作者头像 李华
网站建设 2026/6/18 21:18:41

MPC821嵌入式处理器核心机制:内存映射、时钟与复位管理详解

1. MPC821内存映射:从地址空间到硬件访问的桥梁在嵌入式系统开发中,内存映射(Memory Map)是连接软件与硬件的核心纽带。它不仅仅是手册里的一张地址分配表,更是决定了处理器如何“看见”和“操作”整个系统资源的底层规…

作者头像 李华
网站建设 2026/6/18 21:10:38

企业文档协作困境与kkFileView的工程化解决方案

企业文档协作困境与kkFileView的工程化解决方案 【免费下载链接】kkFileView Universal File Online Preview Project based on Spring-Boot 项目地址: https://gitcode.com/GitHub_Trending/kk/kkFileView 在数字化转型浪潮中,企业面临的核心挑战之一是如何…

作者头像 李华