【问题标题】:Django order by issue when used Q filter with multiple order by and distinct当使用具有多个 order by 和 distinct 的 Q 过滤器时,Django order by issue
【发布时间】:2020-12-25 22:10:43
【问题描述】:

我正在开发一个照片项目,用户可以在该项目中下载点赞照片(也可以进行其他操作)。我有两个模型来跟踪这些信息。以下是使用的模型(Postgres 使用的数据库)。

# Photo model stores photos
# download_count, like_count is stored in the same model as well for easier querying
class Photo(models.Model):
        name = models.CharField(max_length=100, null=True, blank=True)
        image = models.ForeignKey(Image, null=True, on_delete=models.CASCADE)
        download_count = models.IntegerField(default=0)
        like_count = models.IntegerField(default=0)
        views = GenericRelation(
            'Stat', related_name='photo_view',
            related_query_name='photo_view', null=True, blank=True)
        downloads = GenericRelation(
            'Stat', related_name='photo_download',
            related_query_name='photo_download', null=True, blank=True)
    
    
# Stat has generic relationship with photos. So that it can store any stats information
class Stat(models.Model):
        VIEW = 'V'
        DOWNLOAD = 'D'
        LIKE = 'L'
        STAT_TYPE = (
            (VIEW, 'View'),
            (DOWNLOAD, 'Download'),
            (LIKE, 'Like'),
        )
        user = models.ForeignKey(
            User, null=True, blank=True, on_delete=models.SET_NULL)
        content_type = models.ForeignKey(
            ContentType, on_delete=models.CASCADE, default=0)
        object_id = models.PositiveIntegerField()
        content_object = GenericForeignKey()
        stat_type = models.CharField(max_length=2, choices=STAT_TYPE, default=VIEW)
        created_at = models.DateTimeField(auto_now_add=True)
        updated_at = models.DateTimeField(auto_now=True)

我的要求是获取本周流行的照片。流行度得分应考虑点赞数、下载数

我写了下面的查询来获取本周流行的照片,检查本周创建的喜欢或下载。

# week number
current_week = date.today().isocalendar()[1]

photos = Photo.objects.filter(Q(likes__created_at__week=current_week) | Q(downloads__created_at__week=current_week))\
            .order_by('id', 'download_count', 'like_count')\
            .distinct('id')

问题:使用上面的查询,结果集总是按id排序,即使提到了其他字段。

要求:照片应按总喜欢和下载的总和排序,以便按受欢迎程度排序。

考虑到数据库性能,请建议我实现此目标的方法。

谢谢

【问题讨论】:

  • 如果您想按总点赞数和下载量,为什么要按'id' 订购?是否有任何具体理由将其包括在内?由于id 始终是唯一的,因此它始终只会按 id 排序。您是否链接到 Django 中的查询注释和聚合?我想这就是你要找的。​​span>
  • @Exelian 我已经按顺序提到了 id,因为它在 .distinct('id') 中使用。如果我从 order by 中删除它,则查询不会编译。

标签: django database postgresql django-models django-filter


【解决方案1】:

对于这种情况,您可以使用annotate()F object

photos = Photo.objects.filter().annotate(like_download=F('download_count') + F('like_count')).order_by('like_download').distinct()

【讨论】:

  • 好的,但是这个查询没有检查持续时间。我想获取本周有赞和下载的热门照片。
  • 是的,因为我刚刚向您展示了注释的工作并删除了其他部分以使其易于理解。
  • 根据您的建议,我已将查询修改如下。看来结果还不错。你能验证一次吗? Photo.objects.filter(is_active=True)\ .filter(Q(likes__created_at__week=current_week) | Q(downloads__created_at__week=current_week))\ .annotate(score=F('download_count') + F('like_count'))\ . order_by('-score')\.distinct()
【解决方案2】:
Entry.objects.filter(pub_date__year=2005).order_by('-pub_date', 'headline')

上述结果将按 pub_date 降序排列,然后按标题升序排列。 “-pub_date”前面的负号表示降序。

所以如果你给id,它会被id优先排序。

您可以在您的情况下使用annotate。 可以使用 annotate() 子句生成每个对象的摘要。当指定 annotate() 子句时,QuerySet 中的每个对象都将使用指定的值进行注释。

【讨论】:

    【解决方案3】:

    感谢@biplove-lamichhane 建议我注释函数。我可以通过使用以下查询来获得所需的响应

    photos = Photo.objects.filter(is_active=True)\
                    .filter(Q(likes__created_at__week=current_week) | Q(downloads__created_at__week=current_week))\
                    .annotate(score=F('download_count') + F('like_count'))\
                    .order_by('-score')\
                    .distinct()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-11-20
      • 1970-01-01
      • 1970-01-01
      • 2013-01-25
      • 1970-01-01
      • 2021-07-12
      相关资源
      最近更新 更多