J'ai rencontré quelques accrochages avec la réponse acceptée. Voici ma solution.
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
Remarque: cela utilise des solutions qui ne sont pas officiellement approuvées dans les documents Django, et elles pourraient cesser de fonctionner dans les futures versions. J'ai testé cela en 1.9.13.
La première amélioration est qu'elle vous permet de continuer à utiliser l'instance d'origine, en utilisant copy.copy
. Même si vous n'avez pas l'intention de réutiliser l'instance, il peut être plus sûr de faire cette étape si l'instance que vous clonez a été passée comme argument à une fonction. Sinon, l'appelant aura de manière inattendue une instance différente lorsque la fonction reviendra.
copy.copy
semble produire une copie superficielle d'une instance de modèle Django de la manière souhaitée. C'est l'une des choses que je n'ai pas trouvées documentées, mais cela fonctionne en décapant et en décollant, donc c'est probablement bien pris en charge.
Deuxièmement, la réponse approuvée laissera tous les résultats prélus attachés à la nouvelle instance. Ces résultats ne doivent pas être associés à la nouvelle instance, sauf si vous copiez explicitement les relations to-many. Si vous parcourez les relations prélues, vous obtiendrez des résultats qui ne correspondent pas à la base de données. La rupture du code de travail lorsque vous ajoutez une prélecture peut être une mauvaise surprise.
La suppression _prefetched_objects_cache
est un moyen rapide et sale de supprimer tous les préfixes. Les accès ultérieurs à plusieurs fonctionnent comme s'il n'y avait jamais eu de prélecture. L'utilisation d'une propriété non documentée qui commence par un trait de soulignement pose probablement des problèmes de compatibilité, mais cela fonctionne pour l'instant.