Django在Postgres中使用distinct不起作用

3
我正在配置一个API来获取结果列表。这些条目是服装“产品”,每个产品都有几种“变体”。
我试图使用“distinct”确保查询集只返回唯一的产品列表,而不是由于许多变体而重复多次的相同产品。
过去,我使用产品的主键(id)上的distinct。然而,下面的代码没有起作用。
当我尝试使用“distinct”时,我会收到500错误。如果没有它,我就不会出错。我无法在本地测试,因为SQLite不喜欢distinct。我正在使用
class InternalListView(APIView):

    renderer_classes = (JSONRenderer, )

    def get(self, request, *args, **kwargs):

        filters = {}
        for key, value in request.GET.items():
            key = key.lower()
            if key in countmatch:
                lookup, val = internalmatch[key](value.lower())
                filters[lookup] = val

        qset = (
            Product.objects
            .filter(**filters)
            .distinct('id')
            .order_by('-rating')
            .values('name', 'brand', 'rating')
            .annotate(
                price=F('variation__price__price'),
                id=F('pk'),
                vari=F('variation'),
            )
        )

        for i in qset:
            i['likes'] = random.randint(500, 1000)

        print qset

        return Response(qset.all())

1
尝试获取导致500错误的错误消息,并在可能的情况下发布异常的完整堆栈跟踪。但我猜测,错误消息是“SELECT DISTINCT ON expressions must match initial ORDER BY expressions”。distinct()与字段名称是PostgreSQL扩展,只有在distinct()给出的字段也被提供给第一个order_by()时才起作用。 - dhke
一般来说,当你处理这样的问题时,我非常建议安装本地Postgres服务器进行尝试,这并不难。 - RemcoGerlich
1个回答

5

啊哈,我终于明白了。

根据Django文档(https://docs.djangoproject.com/en/1.9/ref/models/querysets/#distinct)的说明:

distinct和order_by必须相同。

所以这个是不行的:

        .distinct('id')
        .order_by('-rating')

但这个可以工作:
        .distinct('id')
        .order_by('id')

并且这是最好的工作方式:

        .distinct('rating', 'id')
        .order_by('-rating')

使用选项3有什么问题吗?


distinct('id') 转化为 SELECT DISTINCT ON,是PostgreSQL扩展。由于distinct()会消除行,PostgreSQL要求您指定一个定义好的顺序,否则它将消除随机的行,导致(潜在地)不可重复的选择。 - dhke
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Andrew
有趣的是,PostgreSQL(9.4.6)只有在order_by中包含至少一个不在distinct列表中的列时才会出错。即SELECT DISTINCT ON(a,b) a,b,c ... ORDER BY a可行。SELECT DISTINCT ON(a,b) a,b,c ... ORDER BY a,c失败,而SELECT DISTINCT ON(a,b) a,b,c ... ORDER BY a,b,c则被接受。对我来说,第一种情况被接受似乎不正确,虽然你可以在输出中得到所有三列,但在第一种情况下,第一行可能是随机的。 - dhke
@Ycon,选项3在语义上与其他两个选项不同。 distinct('id')将消除所有具有相同id的行。 distinct('id','rating')仅删除具有相同“id”和“rating”的重复行。 - dhke
@dhke 有趣...我并没有手动做过很多psql,但我实际上喜欢这种方式。这是在TSQL中的一个hack。我可以看出为什么#3可能有效,但这只是事后的理性化。也许它已经按a和b排序了,所以现在我们可以做c..但如果b不存在,它会变得混乱。 - Andrew
那么我需要做什么才能消除具有重复ID的重复结果并仍按排名排序呢?使用第三个选项并没有帮助。 - DataGreed

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接