2010-10-25 13 views
5

Estoy creando una subclase de un modelo existente. Quiero que muchos de los miembros de la clase de padres ahora, en cambio, sean miembros de la clase infantil.Mover un objeto python/django de un modelo principal a un elemento secundario (subclase)

Por ejemplo, tengo un modelo Swallow. Ahora, estoy haciendo EuropeanSwallow (Swallow) y AfricanSwallow (Swallow). Quiero tomar algunos, pero no todos los objetos Swallow, para convertirlos en EuropeanSwallow o AfricanSwallow, dependiendo de si son migratorios.

¿Cómo puedo moverlos?

Respuesta

4

Sé que esto es mucho más tarde, pero necesitaba hacer algo similar y no pude encontrar mucho. Encontré la respuesta enterrada en algún código fuente here, pero también escribí un ejemplo de método de clase que sería suficiente.

class AfricanSwallow(Swallow): 

    @classmethod 
    def save_child_from_parent(cls, swallow, new_attrs): 
     """ 
     Inputs: 
     - swallow: instance of Swallow we want to create into AfricanSwallow 
     - new_attrs: dictionary of new attributes for AfricanSwallow 

     Adapted from: 
     https://github.com/lsaffre/lino/blob/master/lino/utils/mti.py 
     """ 
     parent_link_field = AfricanSwallow._meta.parents.get(swallow.__class__, None) 
     new_attrs[parent_link_field.name] = swallow 
     for field in swallow._meta.fields: 
      new_attrs[field.name] = getattr(swallow, field.name) 
     s = AfricanSwallow(**new_attrs) 
     s.save() 
     return s 

Sin embargo, no pude averiguar cómo hacer que mi validación de formulario funcione con este método; por lo que ciertamente podría mejorarse más; probablemente significa que una refacturación de la base de datos podría ser la mejor solución a largo plazo ...

+0

Hola, respuesta increíble. Ha pasado un tiempo desde que tuve esta necesidad. Naturalmente, soy un poco reacio a confiar en _meta en una situación de producción, pero así es la vida. ¡Gracias! – jMyles

7

Es un poco de un truco, pero esto funciona:

swallow = Swallow.objects.get(id=1) 
swallow.__class__ = AfricanSwallow 
# set any required AfricanSwallow fields here 
swallow.save() 
+0

Qué hermoso corte, que me ahorró un día . ¡Gracias! – neelix

0

sugiere emplear django-model-utils's InheritanceCastModel. Esta es una implementación que me gusta. Puedes encontrar muchos más en djangosnippets y algunos blogs, pero después de recorrerlos todos, elegí este. Espero eso ayude.

1

Depende del tipo de herencia de modelo que utilizará. Consulte http://docs.djangoproject.com/en/dev/topics/db/models/#model-inheritance para los tres tipos clásicos. Ya que parece que quieres tragar objetos que descarta la clase base abstracta.

Si desea almacenar diversa información en el DB para Swallow vs AfricanSwallow vs EuropeanSwallow, entonces querrá usar MTI. El mayor problema con MTI como recomienda el modelo oficial de django es que el polimorfismo no funciona correctamente. Es decir, si obtiene un objeto Swallow del DB que en realidad es un objeto AfricanSwallow, no obtendrá una instancia de AfricanSwallow. (Ver this question.) Algo como django-model-utils InheritanceManager puede ayudar a superar eso.

Si tiene datos reales que necesita conservar a través de este cambio, use South migrations. Haga dos migraciones: la primera que cambia el esquema y otra que copia los datos de los objetos apropiados en subclases.

0

Otro enfoque (desactualizado): si no te importa conservar la identificación de los padres, puedes crear nuevas instancias secundarias desde los atributos de los padres. Esto es lo que hice:

ids = [s.pk for s in Swallow.objects.all()] 
# I get ids list to avoid memory leak with long lists 
for i in ids: 
    p = Swallow.objects.get(pk=i) 
    c = AfricanSwallow(att1=p.att1, att2=p.att2.....) 
    p.delete() 
    c.save() 

Una vez que esto pasa, una nueva instancia AfricanSwallow se creará la sustitución de cada instancia del trago inicial Tal vez esto ayude a alguien :)

Cuestiones relacionadas