如何在Django views.py中过滤Product模型的categories数组字段并获取去重值
我明白你遇到的困扰了——用普通的values_list('categories', flat=True).distinct()没法拿到数组字段里单个元素的去重值,因为这个写法只会对整个数组做去重,而不是拆分数组内部的内容。下面给你两种靠谱的解决方案(默认你用的是PostgreSQL的ArrayField,这是Django里最常用的数组字段实现):
方法一:用Django内置的Unnest函数(Django 3.2+)
如果你的Django版本在3.2及以上,直接用官方提供的Unnest函数就能轻松拆分数组,再获取去重值:
from django.contrib.postgres.functions import Unnest # 获取所有不重复的分类值 unique_categories = Product.objects.annotate( single_category=Unnest('categories') ).values_list('single_category', flat=True).distinct()
原理很直观:Unnest('categories')会把每个产品的categories数组拆分成单独的行,每行对应一个分类元素;然后我们通过annotate把这些元素命名为single_category,最后用values_list提取并去重。
方法二:自定义Unnest函数(适用于旧版Django)
如果你的Django版本低于3.2,自己定义一个简单的Func类就能实现同样的效果:
from django.db.models import Func class Unnest(Func): function = 'UNNEST' arity = 1 # 执行查询获取去重分类 unique_categories = Product.objects.annotate( single_category=Unnest('categories') ).values_list('single_category', flat=True).distinct()
这里的UNNEST是PostgreSQL自带的函数,专门用来把数组拆分成行数据,我们用Django的Func把它包装成ORM能识别的操作。
为什么原来的写法不行?
你之前用的Product.objects.values_list('categories', flat=True).distinct(),返回的是每个产品的整个categories数组,distinct()只是把重复的数组(比如两个产品都有["电子产品", "手机"]这样的数组)去重,而不会拆分数组里的单个元素——这就是你拿不到想要结果的原因。
备选方案(仅适合小数据集)
如果因为某些限制没法用数据库层面的拆分,也可以在Python代码里处理,但这种方法在产品数据多的时候性能很差,只适合小量数据:
all_categories = [] # 遍历所有产品,把每个产品的分类加到列表里 for product in Product.objects.all(): all_categories.extend(product.categories) # 用集合去重再转成列表 unique_categories = list(set(all_categories))
内容的提问来源于stack exchange,提问作者Dhany P Sukumaran

