Tôi đã gặp một vài vấn đề với câu trả lời được chấp nhận. Đây là giải pháp của tôi.
import copy
def clone(instance):
cloned = copy.copy(instance) # don't alter original instance
cloned.pk = None
try:
delattr(cloned, '_prefetched_objects_cache')
except AttributeError:
pass
return cloned
Lưu ý: điều này sử dụng các giải pháp không được xử phạt chính thức trong các tài liệu Django và chúng có thể ngừng hoạt động trong các phiên bản trong tương lai. Tôi đã thử nghiệm điều này trong 1.9.13.
Cải tiến đầu tiên là nó cho phép bạn tiếp tục sử dụng thể hiện ban đầu, bằng cách sử dụng copy.copy
. Ngay cả khi bạn không có ý định sử dụng lại cá thể, việc thực hiện bước này sẽ an toàn hơn nếu trường hợp bạn nhân bản được truyền dưới dạng đối số cho hàm. Nếu không, người gọi sẽ bất ngờ có một phiên bản khác khi hàm trả về.
copy.copy
dường như tạo ra một bản sao nông của một mô hình Django theo cách mong muốn. Đây là một trong những điều tôi không tìm thấy tài liệu, nhưng nó hoạt động bằng cách tẩy và tháo, vì vậy nó có thể được hỗ trợ tốt.
Thứ hai, câu trả lời được phê duyệt sẽ để lại bất kỳ kết quả tìm nạp nào được đính kèm với trường hợp mới. Những kết quả đó không nên được liên kết với trường hợp mới, trừ khi bạn sao chép rõ ràng các mối quan hệ với nhiều người. Nếu bạn duyệt qua các mối quan hệ được tìm nạp trước, bạn sẽ nhận được kết quả không khớp với cơ sở dữ liệu. Phá vỡ mã làm việc khi bạn thêm một prefetch có thể là một bất ngờ khó chịu.
Xóa _prefetched_objects_cache
là một cách nhanh chóng và bẩn để loại bỏ tất cả các tìm nạp trước. Sau đó, nhiều truy cập hoạt động như thể không bao giờ có một lượt tải trước. Sử dụng một tài sản không có giấy tờ bắt đầu bằng dấu gạch dưới có thể yêu cầu sự cố tương thích, nhưng hiện tại nó hoạt động.