2012-12-04 29 views
21

Tôi có một mô hình có bốn trường. Làm thế nào để loại bỏ các đối tượng trùng lặp khỏi cơ sở dữ liệu của tôi?Django - xóa đối tượng trùng lặp trong đó có nhiều trường để so sánh

Câu trả lời của Daniel Roseman với this question có vẻ phù hợp, nhưng tôi không chắc chắn cách mở rộng trường hợp này thành bốn trường để so sánh cho mỗi đối tượng.

Cảm ơn,

W.

Trả lời

56
unique_fields = ['field_1', …, 'field_n'] 

duplicates = (MyModel.objects.values(*unique_fields) 
          .order_by() 
          .annotate(max_id=models.Max('id'), 
             count_id=models.Count('id')) 
          .filter(count_id__gt=1)) 

for duplicate in duplicates: 
    (MyModel.objects.filter(**{x: duplicate[x] for x in unique_fields}) 
        .exclude(id=duplicate['max_id']) 
        .delete()) 

Bạn không nên làm điều đó thường xuyên. Thay vào đó hãy sử dụng các ràng buộc unique_together trên cơ sở dữ liệu.

tiềm ẩn mã SQL

Khi chú thích django ORM sử dụng GROUP BY tuyên bố trên tất cả các lĩnh vực mô hình sử dụng trong truy vấn. Vì vậy, việc sử dụng phương thức .values(). GROUP BY sẽ nhóm tất cả các bản ghi có các giá trị giống hệt nhau. Những người được sao chép (nhiều hơn một số id cho unique_fields) sau đó được lọc ra trong câu hỏi HAVING được tạo bởi .filter() trên chú thích QuerySet.

SELECT 
    field_1, 
    … 
    field_n, 
    MAX(id) as max_id, 
    COUNT(id) as count_id 
FROM 
    app_mymodel 
GROUP BY 
    field_1, 
    … 
    field_n 
HAVING 
    count_id > 1 

Các bản ghi trùng lặp sau đó sẽ bị xóa trong vòng for ngoại trừ bản ghi thường xuyên nhất cho mỗi nhóm.

.order_by rỗng()

Chỉ cần chắc chắn, nó luôn luôn khôn ngoan để thêm một sản phẩm nào .order_by() gọi trước khi tập hợp một QuerySet.

Các trường được sử dụng để đặt hàng QuerySet cũng được bao gồm trong tuyên bố GROUP BY. Làm trống .order_by() ghi đè các cột được khai báo trong mô hình Meta và kết quả là chúng không được bao gồm trong truy vấn SQL (ví dụ: sắp xếp mặc định theo ngày có thể làm hỏng kết quả).

Bạn có thể không cần phải ghi đè lên tại thời điểm hiện tại, nhưng ai đó có thể thêm thứ tự mặc định sau đó và do đó làm hỏng mã xóa trùng lặp quý giá của bạn thậm chí không biết điều đó. Có, tôi chắc chắn bạn có 100% phạm vi kiểm tra…

Chỉ cần thêm trống .order_by() để an toàn. ;-)

https://docs.djangoproject.com/en/1.11/topics/db/aggregation/#interaction-with-default-ordering-or-order-by

giao dịch

Tất nhiên bạn nên xem xét làm việc đó tất cả trong một giao dịch duy nhất.

https://docs.djangoproject.com/en/1.11/topics/db/transactions/#django.db.transaction.atomic

+0

Cảm ơn! Tuy nhiên, để tôi có thể hiểu (tôi vẫn còn rất nhiều người mới làm quen với Django), bạn có thể giải thích điều gì đang xảy ra ở mỗi bước không? Tôi hiểu rằng 'MyModel.objects.values ​​(* unique_fields)' tạo ra một bộ từ điển, với mỗi từ điển liên quan đến một đối tượng. Nhưng sau đó tôi bị lạc - chú thích đang làm gì? – Westerley

+1

Tôi hy vọng bản cập nhật của tôi sẽ làm rõ mọi thứ một chút. –

+1

Brilliant! Hoạt động hoàn hảo!Nó đã cho tôi khá nhiều nghiên cứu và suy nghĩ để tìm ra chính xác ** cách nó hoạt động (lời giải thích của bạn đã giúp khá nhiều và giúp tôi tìm ra những gì tôi phải đọc ...) nhưng làm việc được! Cảm ơn một lần nữa (và xin lỗi vì sự chậm trễ trong việc trở lại này) – Westerley

Các vấn đề liên quan