假设我有以下Django模型:
class Article(models.Model):
title = models.CharField(max_length=200)
blog = models.CharField(max_length=255)
rating = models.IntegerField(default=0)
class ArticleTag(models.Model):
article = models.ForeignKey(Article)
tag = models.CharField(max_length=200)
添加一些数据:
ArticleID Rating Blog
-----------------------------------------
article1 -> 1 3 CNN
article2 -> 2 2 BBC
article3 -> 3 5 BBC
article4 -> 4 9 NTV
ArticleID tag
-------------------
1 tag1
1 tag2
1 tag3
2 tag1
2 tag4
3 tag5
4 tag6
4 tag7
假设我们有一个喜欢
tag1
、tag2
、tag6
和BBC
的用户。所有条款都符合要求,因为第一条有tag1
和tag2
,第四条有tag1
,第二条和第三条来自BBC
。如果我们按等级订购:
article4
,article3
,article1
,article2
。但是,我需要先按它们拥有的匹配标记数+blog对项目进行排序,然后作为第二个排序参数进行评级。因此,我希望结果按以下顺序排列:
第1条-
tag1
和tag2
,评级=3第2条-
tag1
和BBC
,评级=2第4条-
tag6
,评级=9第3条-
BBC
,评级=5在Django能做到吗?如果不是,那PostgreSQL呢?
最佳答案
SQL查询可能如下所示:
SELECT *
FROM Article a
LEFT JOIN (
SELECT ArticleID, count(*) AS ct
FROM ArticleTag
WHERE tag IN ('tag1', 'tag2', 'tag6') -- your tags here
GROUP BY ArticleID
) t ON t.ArticleID = a.ID
ORDER BY t.ct DESC NULLS LAST
, (a.blog = 'BBC') DESC NULLS LAST -- your blog here
, rating DESC NULLS LAST;
基本上:
在subquery
ArticleID
中为每个t
计算匹配的标记。LEFT JOIN
它的主表,其中包含二级(blog
)和三级(rating
)排序条件的数据。ORDER BY
三个标准,ct
第一个,blog
下一个,rating
最后一个。它们都是递减的(最高值优先)。这也适用于布尔表达式(a.blog = 'BBC')
,因为TRUE
(1)在FALSE
(0)之前按降序排序。重要提示:按降序,空值将首先排序,因此如果可以有空值,则需要
NULLS LAST
(如果不能,则不会造成损害)。PostgreSQL sort by datetime asc, null first?
即使所有列都定义为
NOT NULL
,ct
仍然可以为空,因为LEFT JOIN
。如果Django使用双引号保留混合大小写名称,那么在SQL中也必须这样做。否则,所有标识符都转换为小写。
关于python - 选择所有具有匹配标签的项目,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26828369/