假设我有以下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

假设我们有一个喜欢tag1tag2tag6BBC的用户。所有条款都符合要求,因为第一条有tag1tag2,第四条有tag1,第二条和第三条来自BBC
如果我们按等级订购:article4article3article1article2
但是,我需要先按它们拥有的匹配标记数+blog对项目进行排序,然后作为第二个排序参数进行评级。因此,我希望结果按以下顺序排列:
第1条-tag1tag2,评级=3
第2条-tag1BBC,评级=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;

基本上:
在subqueryArticleID中为每个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 NULLct仍然可以为空,因为LEFT JOIN
如果Django使用双引号保留混合大小写名称,那么在SQL中也必须这样做。否则,所有标识符都转换为小写。

关于python - 选择所有具有匹配标签的项目,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/26828369/

10-12 17:02