Ich bin auf ein paar Fallstricke mit der akzeptierten Antwort gestoßen. Hier ist meine Lösung.
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
Hinweis: Hierbei werden Lösungen verwendet, die in den Django-Dokumenten nicht offiziell genehmigt wurden und in zukünftigen Versionen möglicherweise nicht mehr funktionieren. Ich habe dies in 1.9.13 getestet.
Die erste Verbesserung besteht darin, dass Sie die ursprüngliche Instanz weiterhin verwenden können, indem Sie verwenden copy.copy
. Selbst wenn Sie nicht beabsichtigen, die Instanz wiederzuverwenden, kann es sicherer sein, diesen Schritt auszuführen, wenn die zu klonende Instanz als Argument an eine Funktion übergeben wurde. Wenn nicht, hat der Aufrufer unerwartet eine andere Instanz, wenn die Funktion zurückkehrt.
copy.copy
scheint eine flache Kopie einer Django-Modellinstanz auf die gewünschte Weise zu erzeugen. Dies ist eines der Dinge, die ich nicht dokumentiert gefunden habe, aber es funktioniert durch Beizen und Entpicken, daher wird es wahrscheinlich gut unterstützt.
Zweitens werden bei der genehmigten Antwort alle vorab abgerufenen Ergebnisse an die neue Instanz angehängt. Diese Ergebnisse sollten nicht mit der neuen Instanz verknüpft werden, es sei denn, Sie kopieren die zu vielen Beziehungen explizit. Wenn Sie die vorab abgerufenen Beziehungen durchlaufen, erhalten Sie Ergebnisse, die nicht mit der Datenbank übereinstimmen. Das Brechen des Arbeitscodes beim Hinzufügen eines Prefetch kann eine böse Überraschung sein.
Das Löschen _prefetched_objects_cache
ist eine schnelle und schmutzige Methode, um alle Prefetches zu entfernen. Nachfolgende zu viele Zugriffe funktionieren so, als ob es nie einen Prefetch gegeben hätte. Die Verwendung einer undokumentierten Eigenschaft, die mit einem Unterstrich beginnt, führt wahrscheinlich zu Kompatibilitätsproblemen, funktioniert jedoch vorerst.