Django中查询参数为None时如何优雅实现模型数据过滤
Django 动态查询参数过滤的简洁实现
这是Django ORM使用中非常典型的动态过滤场景,写多层分支判断完全没必要,利用filter支持关键字参数解包的特性就能用非常简洁的代码实现,后续扩展过滤字段也很方便。
最简实现方案
核心逻辑是构造一个过滤条件字典,只把值非空(即参数实际传入了)的字段放进字典,最后把字典解包传给filter方法即可,代码如下:
def get(self, request): query = request.GET filter_kwargs = {} category_id = query.get('category_id') if category_id is not None: filter_kwargs['category_id'] = category_id level = query.get('level') if level is not None: filter_kwargs['level'] = level qs = Theme.objects.filter(**filter_kwargs)
注意避坑
不要用if category_id这种真值判断来决定是否加过滤条件:如果合法参数值是整数0,会被误判为假值跳过过滤,必须用is not None做判断才准确。
更易扩展的写法
如果后续要加更多过滤参数,还可以用字段白名单的方式循环处理,不用重复写判断逻辑:
def get(self, request): # 配置允许作为过滤条件的模型字段,避免传入非法参数导致安全问题 allow_filter_fields = ["category_id", "level"] filter_kwargs = {} for field in allow_filter_fields: value = request.GET.get(field) if value is not None: filter_kwargs[field] = value qs = Theme.objects.filter(**filter_kwargs)
安全提示:必须维护过滤字段白名单,绝对不能直接把
request.GET的所有键值对直接解包传给filter,否则会存在越权查询、SQL注入的风险。
如果项目中过滤场景比较复杂,也可以直接接入Django生态的django-filter库做统一的参数校验和过滤,但就当前的需求场景,上面的原生实现没有额外依赖,逻辑清晰完全够用。
内容的提问来源于stack exchange,提问作者Sergey
相关产品推荐
相关产品推荐

