Django:按外键去重后排序
我有两个模型,分别叫做 Track
和 Pair
。每个 Pair
里都有 track1
、track2
和 popularity
(受欢迎程度)。我想要得到一个按受欢迎程度(从高到低)排序的 Pair
列表,并且确保没有两个 Pair
的 track1
是一样的。以下是我到目前为止尝试过的:
lstPairs = Pair.objects.order_by('-popularity','track1__id').distinct('track1__id')[:iNumPairs].values_list('track1__id', 'track2__id', 'popularity')
这让我遇到了以下错误:
ProgrammingError: SELECT DISTINCT ON expressions must match initial ORDER BY expressions
...所以我又尝试了这个:
lstPairs = Pair.objects.order_by('-popularity','track1__id').distinct('popularity', 'track1__id')[:iNumPairs].values_list('track1__id', 'track2__id', 'popularity')
结果却出现了重复的 track1__id
。有没有人知道怎么解决这个问题?我猜我可能需要用 raw()
或者类似的东西,但我不知道该怎么处理这种情况。我使用的是 PostgreSQL 作为数据库,所以 DISTINCT
应该是可以用的。
2 个回答
查看关于 distinct的文档。
首先:
只有在PostgreSQL数据库中,你可以通过传递位置参数(*fields)来指定要应用DISTINCT的字段名。
你没有说明你的数据库类型,如果不是PostgreSQL,那就没办法实现这个功能。
其次:
当你指定字段名时,必须在QuerySet中提供order_by(),而order_by()中的字段必须和distinct()中的字段顺序一致。
我觉得你可以使用raw(),或者先获取一个按受欢迎程度排序的所有Pairs列表,然后再用Python根据track1的唯一性进行过滤。
首先,我们来澄清一下:DISTINCT
是标准的 SQL,而 DISTINCT ON
是 PostgreSQL 的一个扩展功能。
这个错误信息(DISTINCT ON expressions must match initial ORDER BY expressions
)的意思是,你需要修正你的 ORDER BY
语句,而不是 DISTINCT ON
(如果你去改 DISTINCT ON
,结果会和你之前看到的不同)。
这个
DISTINCT ON
表达式必须和最左边的 ORDER BY 表达式匹配。ORDER BY 语句通常会包含其他表达式,用来决定在每个 DISTINCT ON 组内行的优先顺序。
这样你就能得到你想要的结果:
lstPairs = Pair.objects.order_by('track1__id','-popularity').distinct('track1__id')[:iNumPairs].values_list('track1__id', 'track2__id', 'popularity')
在 SQL 中:
SELECT DISTINCT ON (track1__id) track1__id, track2__id, popularity
FROM pairs
ORDER BY track1__id, popularity DESC
但 可能 顺序不对。
如果你想保持原来的顺序,可以在这里使用一个子查询:
SELECT *
FROM (
SELECT DISTINCT ON (track1__id) track1__id, track2__id, popularity
FROM pairs
ORDER BY track1__id
-- LIMIT here, if necessary
)
ORDER BY popularity DESC, track1__id