2011-11-24 26 views
8

Tôi có một mô hình với ba lĩnh vựcDi chuyển Django mô hình để hạn chế unique_together

class MyModel(models.Model): 
    a = models.ForeignKey(A) 
    b = models.ForeignKey(B) 
    c = models.ForeignKey(C) 

Tôi muốn thực thi một hạn chế duy nhất giữa các trường này, và tìm thấy của django unique_together, mà dường như là giải pháp. Tuy nhiên, tôi đã có cơ sở dữ liệu hiện tại và có nhiều bản sao. Tôi biết rằng kể từ khi unique_together hoạt động ở cấp cơ sở dữ liệu, tôi cần phải độc nhất-ify các hàng, và sau đó thử di chuyển.

Có cách nào tốt để đi về việc loại bỏ các bản sao (trong đó một bản sao có giống nhau (A, B, C)) để tôi có thể chạy di chuyển để có được ràng buộc unique_together không?

+0

làm bạn có bất kỳ lĩnh vực khác trên mô hình của bạn (mà có thể ảnh hưởng đến lựa chọn trong đó trùng lặp để giữ)? – second

+0

tôi có một thời gian created_at mà có lẽ sẽ là chỉ số tốt nhất – jkeesh

Trả lời

22

Nếu bạn vui lòng chọn một trong các bản sao tùy ý, tôi nghĩ những điều sau đây có thể thực hiện thủ thuật. Có lẽ không phải là hiệu quả nhất nhưng đủ đơn giản và tôi đoán bạn chỉ cần chạy điều này một lần. Vui lòng xác minh điều này tất cả hoạt động trên một số dữ liệu thử nghiệm trong trường hợp tôi đã làm điều gì đó ngớ ngẩn, vì bạn sắp xóa một loạt dữ liệu.

Trước tiên, chúng tôi tìm thấy các nhóm đối tượng tạo thành bản sao. Đối với mỗi nhóm, (tùy ý) chọn một "bậc thầy" mà chúng tôi sẽ giữ. Phương pháp của chúng tôi lựa chọn là để chọn một với thấp nhất pk

master_pks = MyModel.objects.values('A', 'B', 'C' 
    ).annotate(Min('pk'), count=Count('pk') 
    ).filter(count__gt=1 
    ).values_list('pk__min', flat=True) 

sau đó chúng ta lặp qua mỗi bậc thầy, và xóa tất cả các bản sao của nó

masters = MyModel.objects.in_bulk(list(master_pks)) 

for master in masters.values(): 
    MyModel.objects.filter(a=master.a, b=master.b, c=master.c 
     ).exclude(pk=master.pk).del_ACCIDENT_PREVENTION_ete() 
+1

Chúng ta có thể làm một cái gì đó tương tự trong tập tin di chuyển chính nó mà sẽ tránh phải chạy thêm kịch bản? – chhantyal

+1

'.del_ACCIDENT_PREVENTION_elte()' là gì? – Dusty

+7

'xóa' với cụm từ' ACCIDENT_PREVENTION' được thêm vào ở giữa để ngăn người vô tình xóa nội dung bằng cách sao chép/dán mã mà không đọc nó – second

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