2011-05-04 145 views
21

¿Hay una manera fácil de eliminar duplicados en la siguiente consulta básica -eliminar duplicados en una consulta de Django

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

Intenté usar duplicado() pero no funcionaba. ¿Podría mostrarme la sintaxis exacta para hacer esta consulta sin duplicados? Gracias.

+2

Cuando se trata de varias filas, consulte: http://stackoverflow.com/questions/13700200/django-remove-duplicate-objects-where-there -is-más-de-uno-campo-para-comparar/13700642 # 13700642 –

Respuesta

64

Esta consulta no le dará duplicados, es decir, le dará todas las filas en la base de datos, ordenadas por correo electrónico.

Sin embargo, supongo que lo que quieres decir es que tienes datos duplicados dentro de tu base de datos. Agregar distinct() aquí no ayudará, porque incluso si solo tiene un campo, también tiene un campo automático id, por lo que la combinación de id + email no es única.

Suponiendo que sólo necesita un campo, email_address, de-duplicado, se puede hacer esto:

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

Sin embargo, realmente debería solucionar el problema de raíz, y eliminar los datos duplicados de su base de datos.

ejemplo, al eliminar correos electrónicos duplicados de campo de correo electrónico:

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() 

o libros por su nombre:

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() 
+0

Gran solución. Al usar '.values ​​(..)', incluso podría pasar eso como kwargs a '.filter (...)' – vdboor

+0

En el segundo ejemplo de código, ¿deberíamos establecer el vairable para eliminar todos los duplicados de correos electrónicos?porque una vez que finaliza la iteración, Email.objects se convierte en el conjunto completo de objetos de correo electrónico, ¿no es así? – nextdoordoc

3

Puede utilizar la función distinct(), dependiendo de su modelo. Si sólo desea recuperar un solo campo formar el modelo, se podría hacer algo como:

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

que se debe dar una lista ordenada de correos electrónicos.

0

que utiliza lo siguiente para quitar realmente las entradas duplicadas de la base de datos, espero que esto ayuda alguien más.

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

La implementación de bucles alrededor de las operaciones de ORM generalmente es una mala idea, ya que no se escala muy bien. En este ejemplo, tiene muchas, muchas consultas en ejecución. Supongamos que hay muchas filas devueltas en 'adds'. En cada bucle, se lanza una primera consulta para ver si 'i not in d', y posiblemente otro para eliminar los registros' address' afectados. Puede hacer esto en el ORM directamente sin el ciclo de Python haciendo algo como: 'Address.objects.exclude (pk__in = d.values ​​('pk, flat = True)). Delete()'. (Es posible que deba modificar esto, no lo he probado). – BillyBBone

+0

Gracias por la sugerencia –

2

Para la comprobación de duplicados que puede hacer una GROUP_BY y HAVING en Django de la siguiente manera. Estamos utilizando Django annotations aquí.

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) 

Ahora bucle a través de los datos anteriores y borrando todos los demás emails excepto el primero (depende del requisito o lo que sea).

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

Puede también utilizar set()

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