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?
Cómo hacerlo, se agregó a los documentos oficiales de Django en Django1.4
https://docs.djangoproject.com/en/1.10/topics/db/queries/#copying-model-instances
La respuesta oficial es similar a la de miah, pero los documentos señalan algunas dificultades con la herencia y los objetos relacionados, por lo que probablemente debería asegurarse de leer los documentos.
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()