Foo.objects.get(pk="foo")
<Foo: test>
Dans la base de données, je veux ajouter un autre objet qui est une copie de l'objet ci-dessus.
Supposons que ma table a une rangée. Je veux insérer le premier objet de la ligne dans une autre ligne avec une clé primaire différente. Comment puis je faire ça?
Il suffit de changer la clé primaire de votre objet et d’exécuter save ().
obj = Foo.objects.get(pk=<some_existing_pk>)
obj.pk = None
obj.save()
Si vous voulez une clé générée automatiquement, définissez la nouvelle clé sur Aucune.
Plus sur UPDATE/INSERT ici .
La documentation de Django pour les requêtes de base de données comprend une section sur la copie d'instances de modèle . En supposant que vos clés primaires soient générées automatiquement, vous obtenez l'objet que vous souhaitez copier, définissez la clé primaire sur None
et enregistrez-le à nouveau:
blog = Blog(name='My blog', tagline='Blogging is easy')
blog.save() # blog.pk == 1
blog.pk = None
blog.save() # blog.pk == 2
Dans cet extrait, la première save()
crée l'objet d'origine et la seconde save()
crée la copie.
Si vous continuez à lire la documentation, vous trouverez également des exemples sur la façon de traiter deux cas plus complexes: (1) copier un objet qui est une instance d’une sous-classe de modèle et (2) copier également des objets connexes, y compris des objets de plusieurs -de nombreuses relations.
Note sur la réponse de miah: La réponse de miah mentionne le paramètre pk sur None
, bien qu'il ne soit pas présenté au premier plan. Donc, ma réponse sert principalement à souligner cette méthode comme la méthode recommandée par Django.
Note historique: Cela n'a pas été expliqué dans les documents Django jusqu'à la version 1.4. Cela a été possible depuis avant 1.4, cependant.
Fonctionnalités futures possibles: La modification susmentionnée de la documentation a été effectuée dans ce ticket . Dans le fil de commentaire du ticket, des discussions ont également eu lieu sur l'ajout d'une fonction copy
intégrée pour les classes de modèle, mais pour autant que je sache, ils ont décidé de ne pas encore s'attaquer à ce problème. Donc, cette manière "manuelle" de copier devra probablement être faite pour le moment.
Soyez prudent ici. Cela peut être extrêmement coûteux si vous êtes dans une boucle et que vous récupérez des objets un à un. Si vous ne voulez pas appeler la base de données, faites simplement:
from copy import deepcopy
new_instance = deepcopy(object_you_want_copied)
new_instance.id = None
new_instance.save()
Il fait la même chose que certaines de ces autres réponses, mais il ne demande pas à la base de données de récupérer un objet. Ceci est également utile si vous souhaitez copier un objet qui n'existe pas encore dans la base de données.
Il y a un extrait de clone ici , que vous pouvez ajouter à votre modèle et qui fait ceci:
def clone(self):
new_kwargs = dict([(fld.name, getattr(old, fld.name)) for fld in old._meta.fields if fld.name != old._meta.pk]);
return self.__class__.objects.create(**new_kwargs)
Comment faire cela a été ajouté à la documentation officielle de Django dans Django1.4
https://docs.djangoproject.com/fr/1.10/topics/db/queries/#copying-model-instances
La réponse officielle est similaire à la réponse de miah, mais les documents soulignent certaines difficultés liées à l'héritage et aux objets associés. Vous devez donc probablement vous assurer de les lire.
Utilisez le code ci-dessous:
from Django.forms import model_to_dict
instance = Some.objects.get(slug='something')
kwargs = model_to_dict(instance, exclude=['id'])
new_instance = Some.objects.create(**kwargs)
définir pk sur Aucun est préférable, Sinse Django peut créer correctement un pk pour vous.
object_copy = MyObject.objects.get(pk=...)
object_copy.pk = None
object_copy.save()
J'ai rencontré un couple de marre 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: ceci utilise des solutions qui ne sont pas officiellement approuvées dans la documentation Django et risquent de ne plus fonctionner dans les versions futures. J'ai testé cela en 1.9.13.
La première amélioration est que cela 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 prudent d'effectuer cette étape si l'instance que vous clonez a été transmise en tant qu'argument à une fonction. Sinon, l'appelant aura inopinément une instance différente au retour de la fonction.
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ée documentée, mais cela fonctionne en décapant et décapant, elle est donc probablement bien prise en charge.
Deuxièmement, la réponse approuvée laissera tous les résultats prélus en amont attachés à la nouvelle instance. Ces résultats ne doivent pas être associés à la nouvelle instance, sauf si vous copiez explicitement les relations à plusieurs. Si vous parcourez les relations prélues à l'avance, vous obtiendrez des résultats qui ne correspondent pas à la base de données. Interrompre le code de travail lorsque vous ajoutez une prélecture peut être une mauvaise surprise.
La suppression de _prefetched_objects_cache
est un moyen rapide et efficace d’éliminer tous les prélèvements. Les accès suivants à plusieurs fonctionnent comme s'il n'y avait jamais eu de prélecture. L'utilisation d'une propriété non documentée commençant par un trait de soulignement pose probablement un problème de compatibilité, mais cela fonctionne pour le moment.
Essaye ça
original_object = Foo.objects.get(pk="foo")
v = vars(original_object)
v.pop("pk")
new_object = Foo(**v)
new_object.save()
C'est un autre moyen de cloner l'instance de modèle:
d = Foo.objects.filter(pk=1).values().first()
d.update({'id': None})
duplicate = Foo.objects.create(**d)
Pour cloner un modèle avec plusieurs niveaux d'héritage, à savoir> = 2 ou ModelC ci-dessous
class ModelA(models.Model):
info1 = models.CharField(max_length=64)
class ModelB(ModelA):
info2 = models.CharField(max_length=64)
class ModelC(ModelB):
info3 = models.CharField(max_length=64)
Veuillez vous référer à la question ici .