【问题标题】:get all instances of a model while removing duplicates based on a field while also attaching the count of the same field获取模型的所有实例,同时根据字段删除重复项,同时附加同一字段的计数
【发布时间】:2020-10-13 22:47:05
【问题描述】:
class Titlecomplaint(models.Model):
    title= models.ForeignKey("titles.title", on_delete= models.CASCADE)
    user= models.ForeignKey("auth.user", on_delete= models.CASCADE)
    content = models.TextField(max_length=250,null=True,blank=True)

从上面的模型中,我只需要获取按照模型中相同标题数量排序的每个标题的一份副本,同时还需要计算数量。

 the_titles= Titlecomplaint.objects.annotate(cnt=Count("title")).values_list('title', flat=True).distinct().order_by("cnt")

我正在尝试上面的 ORM,但它只返回整数,而我需要处理查询对象。

【问题讨论】:

    标签: django database orm


    【解决方案1】:

    如果你想要一个对象列表而不是值列表,你只需要删除values_list 方法并使用以下类似:

    the_titles= Titlecomplaint.objects.annotate(cnt=Count("title")).distinct("title").order_by("cnt")
    

    【讨论】:

    • 非常感谢,但这个不会删除重复的标题。
    【解决方案2】:

    由于聚合 (Count),您在逻辑上只能接收到 {title, count}dict,因为该计数不属于任何特定的 Titlecomplaint 实例。想象一下,有 3 个用户对同一个标题提出 3 个投诉。我们应该在 count=3 时选择哪一个?但是,如果确切需要哪个Titlecomplaint 实例并不重要,则可以通过使用Subquery 来克服。因此,我们以相同的方式开始获取对 title=>count(通过 Django 文档、values + annotate、order_by 移动标准方式以清除任何默认排序)。

    title_counts = Titlecomplaint.objects.order_by().values('title').annotate(cnt=Count('title'))
    

    接下来,让我们使用Subquery为每个Titlecomplaint添加cnt

    title_counts = title_counts.filter(title=OuterRef('title')).values('cnt')
    titles = Titlecomplaint.objects.annotate(cnt=Subquery(title_counts))
    

    最后,每个标题只留下 1 个(随机)Titlecomplaint 并按分排序。

    titles = titles.order_by('cnt', 'title').distinct('cnt', 'title')
    

    最后一个查询仅适用于 PostgreSQL。如果您有另一个数据库,则需要另一种解决方案来为每个标题选择不同的 Titlecomplaint。

    【讨论】:

    • 非常感谢@Alexandr Tatarinov,如果数量可以根据数量相等的日期订购吗?赞赏。
    • titles.order_by('cnt', 'title', 'date').distinct('cnt', 'title') 应该可以工作
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-06-23
    • 2020-08-27
    相关资源
    最近更新 更多