2011-01-19 34 views

Respuesta

286

acaba de cambiar la clave principal de su objeto y ejecutar save().

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

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

Más sobre ACTUALIZACIÓN/INSERCIÓN here.

+2

Merece la pena señalar que esto cita a Django 1.2, ahora estamos a la altura de Django 1.4. No he probado si esto funciona o no, pero no use esta respuesta sin estar seguro de que funciona para usted. – Joe

+3

Funciona bien en 1.4.1 Esta es probablemente una de esas cosas que continuarán funcionando durante mucho tiempo. – frnhr

+0

esta no es una solución general para cuando tienes una base de datos con claves primarias automáticas ... adivinar una clave primaria no utilizada parece una mala idea. – FizxMike

16

Hay un fragmento de clon here, que se puede añadir 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) 
+0

Segundo método actualizará la misma fila. – user426795

+0

@ user426975 - ah, oh bien (lo he quitado de mi respuesta). –

104

La documentación de Django para las consultas de la base de datos incluye a section on copying model instances. Suponiendo sus claves primarias son generados automáticamente, se obtiene el objeto que desea copiar, establece la clave principal para None, y guardar el objeto de nuevo:

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, la primera 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) copiar objetos relacionados, incluidos objetos en relaciones de muchos a muchos.


Nota sobre la respuesta de miah: Ajuste del pk a None se menciona en la respuesta de Miah, aunque no se presentó frente y al centro. Entonces mi respuesta principalmente sirve para enfatizar ese método como la manera recomendada por Django para hacerlo.

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

Posible funcionalidad futura: el cambio de documentos mencionado anteriormente se realizó en this ticket. En el hilo de comentarios del ticket, también se discutió sobre cómo agregar una función integrada de copy para las clases de modelo, pero hasta donde sé, decidieron no abordar ese problema todavía. Entonces, esta forma "manual" de copia probablemente tenga que ver por ahora.

+0

¡El enlace de la documentación original es útil! – haudoing

16

Cómo hacer esto se añadió 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 respuesta de Miah, pero los documentos señalan algunas dificultades con la herencia y los objetos relacionados, por lo tanto, probablemente debería asegurarse de leer los documentos.

+0

cuando abre el enlace dice que no encontró la página – amrit

+0

Los documentos ya no existen para Django 1.4. Actualizaré la respuesta para señalar los últimos documentos. –

+1

@MichaelBylstra Una buena forma de tener enlaces perennes es usar 'stable' en lugar del número de versión en la URL, así: https://docs.djangoproject.com/en/stable/topics/db/queries/#copying -model-instances – Flimm

32

Tenga cuidado aquí. Esto puede ser extremadamente costoso si estás en un ciclo de algún tipo y estás recuperando objetos uno por uno.Si no desea que la llamada a la base de datos, acaba de hacer:

from copy import deepcopy 

new_instance = deepcopy(object_you_want_copied) 
new_instance.id = None 
new_instance.save() 

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

+0

Esto funciona muy bien si tiene un objeto, puede copiar profundamente el objeto original antes de hacer cambios para hacer cambios en el nuevo objeto y guardarlo. Luego puede hacer alguna comprobación de condición y dependiendo de si pasan, es decir, el objeto está en otra tabla que está verificando, puede configurar new_instance.id = original_instance.id y guardar :) ¡Gracias! – radtek

+1

Esto no funciona si el modelo tiene múltiples niveles de herencia. –

+3

Y no funciona con relaciones 'directas' –

16

usar 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) 
+5

'model_to_dict' toma un parámetro' exclude', lo que significa que no necesita el 'pop' separado:' model_to_dict (instance, exclude = ['id']) ' – georgebrock

+0

Eso es genial. Actualizo la respuesta. –

+8

Esto no funciona con los campos ForeignKey – azuax

4

establecer pk en Ninguno es mejor, sinse Django puede crear correctamente un pk para usted

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

clonar una variante con varios niveles de herencia, es decir,> = 2, o ModelC 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 refiérase a la pregunta here.

0

probar este

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