【问题标题】:Remove duplicates in a Django query删除 Django 查询中的重复项
【发布时间】:2011-08-18 03:37:48
【问题描述】:

有没有一种简单的方法可以在以下基本查询中删除重复项:

email_list = Emails.objects.order_by('email')

我尝试使用duplicate(),但它不起作用。执行此查询而不重复的确切语法是什么?

【问题讨论】:

标签: sql django


【解决方案1】:

这个查询不会给你重复 - 即,它会给你数据库中的所有行,通过电子邮件排序。

但是,我认为您的意思是您的数据库中有重复的数据。在此处添加distinct() 将无济于事,因为即使您只有一个字段,您也有一个自动的id 字段 - 所以 id+email 的组合不是唯一的。

假设你只需要一个字段,email_address,去重复,你可以这样做:

email_list = Email.objects.values_list('email', flat=True).distinct()

但是,您应该真正解决根本问题,并从数据库中删除重复数据。

例如,通过电子邮件字段删除重复的电子邮件:

for email in Email.objects.values_list('email', flat=True).distinct():
    Email.objects.filter(pk__in=Email.objects.filter(email=email).values_list('id', flat=True)[1:]).delete()

或按名称的书籍:

for name in Book.objects.values_list('name', flat=True).distinct(): 
    Book.objects.filter(pk__in=Artwork.objects.filter(name=name).values_list('id', flat=True)[3:]).delete()

【讨论】:

  • 很好的解决方案。使用 .values(..) 时,您甚至可以将其作为 kwargs 传递给 .filter(...)
  • 在第二个代码示例中,我们应该设置变量以删除所有重复的电子邮件?因为一旦迭代完成,Email.objects 就变成了 Email 对象的整个查询集,不是吗?
  • 在第二个例子中 [3:] 我觉得很奇怪
  • 谈治本,省了我很多时间!谢谢
【解决方案2】:

为了检查重复,您可以在Django 中执行GROUP_BYHAVING,如下所示。我们在这里使用 Django annotations

from django.db.models import Count
from app.models import Email

duplicate_emails = Email.objects.values('email').annotate(email_count=Count('email')).filter(email_count__gt=1)

现在遍历上述数据并删除除第一个之外的所有其他emails(取决于要求或其他)。

for data in duplicates_emails:
    email = data['email']
    Email.objects.filter(email=email).order_by('pk')[1:].delete()

【讨论】:

    【解决方案3】:

    您可以在查询集的末尾链接.distinct() 以过滤重复项。签出:http://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.distinct

    【讨论】:

    • 你没有理解问题。
    【解决方案4】:

    您可以使用distinct() 函数,具体取决于您的型号。如果您只想从模型中检索单个字段,您可以执行以下操作:

    email_list = Emails.objects.values_list('email').order_by('email').distinct()
    

    这应该会给你一个有序的电子邮件列表。

    【讨论】:

      【解决方案5】:

      你也可以使用set()

      email_list = set(Emails.objects.values_list('email', flat=True))
      

      【讨论】:

      • 在创建两个查询集的联合后,我试图删除重复项。我尝试使用 distinct 方法并将 all 设置为 false qs_1.union(qs_2, all=False)。无法使上述任何一项工作,因此使用了设置。
      • 注意事项:我遇到了这个问题,set() 可以删除重复的记录,但它似乎破坏了 order_by(无论我在之前还是之后应用它)
      【解决方案6】:

      我使用以下方法从数据库中实际删除了重复条目,希望这对其他人有所帮助。

      adds = Address.objects.all()
      d = adds.distinct('latitude', 'longitude')
      for address in adds:    
        if i not in d:
          address.delete()
      

      【讨论】:

      • 围绕 ORM 操作实现循环通常是一个坏主意,因为它不能很好地扩展。在这个例子中,你有很多很多的查询正在执行。假设adds 中返回了许多行。在每个循环中,您启动第一个查询以查看是否为i not in d,并可能启动另一个查询以删除受影响的address 记录。您可以通过执行以下操作直接在 ORM 中执行此操作,而无需 Python 循环:Address.objects.exclude(pk__in=d.values('pk, flat=True)).delete()。 (您可能需要对此进行调整——我还没有测试过)。
      • BillyBBone 的好建议。添加一个小的修正。 values() 没有 flat=True。这里应该使用 values_list():Address.objects.exclude(pk__in=d.values_list('pk', flat=True)).delete()。因为 flat=True 会删除元组并返回列表
      【解决方案7】:

      您可以使用这个原始查询:your_model.objects.raw("select * from appname_Your_model group by column_name")

      【讨论】:

        【解决方案8】:

        使用,自我queryset.annotate()

        from django.db.models import Subquery, OuterRef
        
        email_list = Emails.objects.filter(
            pk__in = Emails.objects.values('emails').distinct().annotate(
                pk = Subquery(
                Emails.objects.filter(
                  emails= OuterRef("emails")
                )
                .order_by("pk")
                .values("pk")[:1])
            )
            .values_list("pk", flat=True)
        )
        

        这个查询集用来进行这个查询。

         SELECT `email`.`id`,
                `email`.`title`,
                `email`.`body`,
               ...
               ...
          FROM `email`
         WHERE `email`.`id` IN (
                SELECT DISTINCT (
                        SELECT U0.`id`
                          FROM `email` U0
                         WHERE U0.`email` = V0.`approval_status`
                         ORDER BY U0.`id` ASC
                         LIMIT 1
                       ) AS `pk`
                 FROM `agent` V0
         )
        

        小抄

        from django.db.models import Subquery, OuterRef
        
        group_by_duplicate_col_queryset = Models.objects.filter(
            pk__in = Models.objects.values('duplicate_col').distinct().annotate(
                pk = Subquery(
                Models.objects.filter(
                  duplicate_col= OuterRef('duplicate_col')
                )
                .order_by("pk")
                .values("pk")[:1])
            )
            .values_list("pk", flat=True)
        )
        

        【讨论】:

          猜你喜欢
          • 2018-10-26
          • 2012-11-02
          • 1970-01-01
          • 2016-12-29
          • 2016-11-07
          • 2019-12-11
          • 2019-03-19
          • 1970-01-01
          • 2014-07-03
          相关资源
          最近更新 更多