2011-05-04 24 views
21

Có một cách đơn giản để loại bỏ bản sao trong truy vấn cơ bản sau -Hủy bỏ bản sao trong một truy vấn django

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

Tôi đã cố gắng sử dụng lặp lại() nhưng nó đã không làm việc. Bạn có thể vui lòng cho tôi biết cú pháp chính xác để thực hiện truy vấn này mà không có bản sao không? Cảm ơn bạn.

+2

Khi giao dịch với nhiều hàng, vui lòng xem: http://stackoverflow.com/questions/13700200/django-remove-duplicate-objects-where-there - nhiều hơn một trường để so sánh/13700642 # 13700642 –

Trả lời

64

Truy vấn này sẽ không cung cấp cho bạn các bản sao - tức là, nó sẽ cung cấp cho bạn tất cả các hàng trong cơ sở dữ liệu, được sắp xếp theo email.

Tuy nhiên, tôi đoán ý của bạn là bạn có dữ liệu trùng lặp trong cơ sở dữ liệu. Thêm distinct() vào đây sẽ không hữu ích, bởi vì ngay cả khi bạn chỉ có một trường, bạn cũng có trường tự động id - do đó, kết hợp id + email không phải là duy nhất.

Giả sử bạn chỉ cần một lĩnh vực, email_address, de-sao chép, bạn có thể làm điều này:

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

Tuy nhiên, bạn thực sự cần giải quyết vấn đề gốc rễ, và loại bỏ các dữ liệu trùng lặp khỏi cơ sở dữ liệu của bạn.

Ví dụ, xóa email trùng lặp bởi trường email:

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

Hoặc sách theo tên:

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

Giải pháp tuyệt vời. Khi sử dụng '.values ​​(..)', bạn thậm chí có thể truyền nó như kwargs thành '.filter (...)' – vdboor

+0

Trong ví dụ mã 2, chúng ta nên đặt varaible để xóa tất cả các bản sao của email?gây ra một lần lặp lại, Email.objects trở thành toàn bộ queryset của các đối tượng Email, phải không? – nextdoordoc

3

Bạn có thể sử dụng chức năng distinct(), tùy thuộc vào kiểu máy của bạn. Nếu bạn chỉ muốn truy xuất một trường đơn mẫu, bạn có thể làm một việc gì đó như:

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

sẽ cung cấp cho bạn danh sách email được sắp xếp.

0

tôi đã sử dụng sau đây để thực sự loại bỏ các mục trùng lặp khỏi từ cơ sở dữ liệu, hy vọng điều này sẽ giúp một người nào khác.

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

Thực hiện vòng lặp xung quanh các hoạt động ORM thường là một ý tưởng tồi, vì nó không quy mô rất tốt. Trong ví dụ này, bạn có nhiều, nhiều truy vấn được thực hiện. Giả sử có nhiều hàng được trả về trong 'bổ sung'. Trong mỗi vòng lặp, bạn khởi chạy một truy vấn đầu tiên để xem liệu 'i not in d', và có thể là một truy vấn khác để xóa các bản ghi' địa chỉ' bị ảnh hưởng. Bạn có thể làm điều này trong ORM trực tiếp mà không có vòng lặp Python bằng cách làm một cái gì đó như: 'Address.objects.exclude (pk__in = d.values ​​('pk, flat = True)). Delete()'. (Bạn có thể cần phải tinh chỉnh điều này - Tôi chưa thử nghiệm). – BillyBBone

+0

Cảm ơn mẹo –

2

Đối với việc kiểm tra trùng lặp bạn có thể làm một GROUP_BYHAVING trong Django như dưới đây. Chúng tôi đang sử dụng Django annotations tại đây.

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) 

Bây giờ lặp qua dữ liệu trên và xóa tất cả các khác emails trừ dữ liệu đầu tiên (phụ thuộc vào yêu cầu hoặc bất kỳ thứ gì).

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

Bạn cũng có thể sử dụng set()

email_list = set(Emails.objects.values_list('email', flat=True)) 
Các vấn đề liên quan