type queryset query example python django django-models

python - queryset - ¿Cómo puedo clonar un objeto de instancia de modelo Django y guardarlo en la base de datos?



models py python (10)

Aquí hay un fragmento de clon, que puede agregar a su modelo que hace esto:

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)

Foo.objects.get(pk="foo") <Foo: test>

En la base de datos, quiero agregar otro objeto que sea una copia del objeto anterior.

Supongamos que mi mesa tiene una fila. Quiero insertar el primer objeto de fila en otra fila con una clave principal diferente. ¿Cómo puedo hacer eso?



La documentación de Django para consultas de bases de datos incluye una sección sobre cómo copiar instancias de modelos . Suponiendo que las claves primarias se generen automáticamente, obtendrá el objeto que desea copiar, establezca la clave primaria en None y vuelva a guardar el objeto:

blog = Blog(name=''My blog'', tagline=''Blogging is easy'') blog.save() # blog.pk == 1 blog.pk = None blog.save() # blog.pk == 2

En este fragmento, el primer save() crea el objeto original, y el segundo save() crea la copia.

Si sigue leyendo la documentación, también hay ejemplos sobre cómo manejar dos casos más complejos: (1) copiar un objeto que es una instancia de una subclase modelo, y (2) también copiar objetos relacionados, incluidos objetos en varios a -Muchas relaciones.

Nota sobre la respuesta de miah: la configuración de pk en None se menciona en la respuesta de miah, aunque no se presenta al frente y al centro. Así que mi respuesta sirve principalmente para enfatizar ese método como la forma recomendada por Django de hacerlo.

Nota histórica: esto no se explicó en los documentos de Django hasta la versión 1.4. Aunque ha sido posible desde antes del 1.4.

Posible funcionalidad futura: El cambio de documentos mencionado anteriormente se realizó en este ticket . En el hilo de comentarios del ticket, también hubo cierta discusión sobre la adición de una función de copy incorporada para las clases modelo, pero por lo que sé, decidieron no abordar ese problema todavía. Así que esta forma "manual" de copiar probablemente tendrá que hacerlo por ahora.


Me he encontrado con un par de errores con la respuesta aceptada. Aquí está mi solución.

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

Nota: esto utiliza soluciones que no están autorizadas oficialmente en los documentos de Django y pueden dejar de funcionar en futuras versiones. He probado esto en 1.9.13.

La primera mejora es que le permite continuar usando la instancia original, utilizando copy.copy . Incluso si no pretende reutilizar la instancia, puede ser más seguro realizar este paso si la instancia que está clonando se pasó como un argumento a una función. Si no, la persona que llama tendrá inesperadamente una instancia diferente cuando la función regrese.

copy.copy parece producir una copia superficial de una instancia de modelo de Django de la forma deseada. Esta es una de las cosas que no encontré documentada, pero funciona decapando y despegando, por lo que es probable que esté bien soportada.

En segundo lugar, la respuesta aprobada dejará los resultados preconfigurados adjuntos a la nueva instancia. Esos resultados no deben asociarse con la nueva instancia, a menos que copie explícitamente las relaciones de muchos. Si atraviesa las relaciones precargadas, obtendrá resultados que no coinciden con la base de datos. Romper el código de trabajo cuando agrega un prefetch puede ser una sorpresa desagradable.

Eliminar _prefetched_objects_cache es una forma rápida y sucia de eliminar todos los prefetches. Los accesos posteriores a muchos funcionan como si nunca hubiera habido una captación previa. El uso de una propiedad no documentada que comienza con un guión bajo probablemente está pidiendo problemas de compatibilidad, pero por ahora funciona.


Para clonar un modelo con múltiples niveles de herencia, es decir,> = 2, o ModelC a continuación

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)

Por favor, consulte la pregunta here .


Prueba esto

original_object = Foo.objects.get(pk="foo") v = vars(original_object) v.pop("pk") new_object = Foo(**v) new_object.save()


Simplemente cambie la clave principal de su objeto y ejecute save ().

obj = Foo.objects.get(pk=<some_existing_pk>) obj.pk = None obj.save()

Si desea una clave generada automáticamente, establezca la nueva clave en Ninguna.

Más sobre ACTUALIZAR / INSERTAR here .


Ten cuidado aqui Esto puede ser extremadamente costoso si está en un bucle de algún tipo y está recuperando objetos uno por uno. Si no desea la llamada a la base de datos, simplemente haga lo siguiente:

from copy import deepcopy new_instance = deepcopy(object_you_want_copied) new_instance.id = None new_instance.save()

Hace lo mismo que algunas de estas otras respuestas, pero no hace que la base de datos llame para recuperar un objeto. Esto también es útil si desea hacer una copia de un objeto que aún no existe en la base de datos.


Usa el siguiente código:

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)


configurar pk a None es mejor, sinse Django puede crear correctamente un pk para ti

object_copy = MyObject.objects.get(pk=...) object_copy.pk = None object_copy.save()