【发布时间】:2011-08-18 03:37:48
【问题描述】:
有没有一种简单的方法可以在以下基本查询中删除重复项:
email_list = Emails.objects.order_by('email')
我尝试使用duplicate(),但它不起作用。执行此查询而不重复的确切语法是什么?
【问题讨论】:
-
This 是解决问题的答案,使用自己 group by,返回 QuerySet。
有没有一种简单的方法可以在以下基本查询中删除重复项:
email_list = Emails.objects.order_by('email')
我尝试使用duplicate(),但它不起作用。执行此查询而不重复的确切语法是什么?
【问题讨论】:
这个查询不会给你重复 - 即,它会给你数据库中的所有行,通过电子邮件排序。
但是,我认为您的意思是您的数据库中有重复的数据。在此处添加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(...)
为了检查重复,您可以在Django 中执行GROUP_BY 和HAVING,如下所示。我们在这里使用 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()
【讨论】:
您可以在查询集的末尾链接.distinct() 以过滤重复项。签出:http://docs.djangoproject.com/en/dev/ref/models/querysets/#django.db.models.query.QuerySet.distinct
【讨论】:
您可以使用distinct() 函数,具体取决于您的型号。如果您只想从模型中检索单个字段,您可以执行以下操作:
email_list = Emails.objects.values_list('email').order_by('email').distinct()
这应该会给你一个有序的电子邮件列表。
【讨论】:
你也可以使用set()
email_list = set(Emails.objects.values_list('email', flat=True))
【讨论】:
我使用以下方法从数据库中实际删除了重复条目,希望这对其他人有所帮助。
adds = Address.objects.all()
d = adds.distinct('latitude', 'longitude')
for address in adds:
if i not in d:
address.delete()
【讨论】:
adds 中返回了许多行。在每个循环中,您启动第一个查询以查看是否为i not in d,并可能启动另一个查询以删除受影响的address 记录。您可以通过执行以下操作直接在 ORM 中执行此操作,而无需 Python 循环:Address.objects.exclude(pk__in=d.values('pk, flat=True)).delete()。 (您可能需要对此进行调整——我还没有测试过)。
您可以使用这个原始查询:your_model.objects.raw("select * from appname_Your_model group by column_name")
【讨论】:
使用,自我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)
)
【讨论】: