2010-10-13 17 views
5

Todavía estoy un poco confundido acerca de la relación de los modelos Proxy con sus Superclases en django. Mi pregunta ahora es ¿cómo obtengo una instancia de un modelo Proxy a partir de una instancia ya recuperada de la Superclase?usando django, ¿cómo construyo una instancia de objeto proxy de una instancia de objeto de superclase?

Por lo tanto, digamos que tengo:

class Animal(models.Model): 
    type = models.CharField(max_length=20) 
    name = models.CharField(max_length=40) 

class Dog(Animal): 
    class Meta: 
     proxy = True 

    def make_noise(self): 
     print "Woof Woof" 

Class Cat(Animal): 
    class Meta: 
     proxy = True 

    def make_noise(self): 
     print "Meow Meow" 

animals = Animal.objects.all() 
for animal in animals: 
    if (animal.type == "cat"): 
     animal_proxy = # make me a cat 
    elif (animal.type == "dog"): 
     animal_proxy = # make me a dog 
    animal_proxy.make_noise() 

OK. Así que .. ¿Qué pasa en que no requiere una consulta de nuevo a la base de datos como "# Me hacen un gato":

animal_proxy = Cat.objects.get(id=animal.id) 

¿Hay una manera simple de crear una instancia de gato desde una instancia de Animal que yo sé que es un gato?

Respuesta

5

Está intentando implementar la persistencia para una jerarquía de herencia. Usar una mesa de concreto y un interruptor type es una buena manera de hacerlo. Sin embargo, creo que su puesta en práctica, en concreto:

for animal in animals: 
    if (animal.type == "cat"): 
     animal_proxy = # make me a cat 

va a contrapelo de Django. El tipo de conexión no debe ser ajeno a la clase proxy (o modelo).

Si yo fuera usted, me gustaría hacer lo siguiente:

En primer lugar, añadir un "tipo de cuenta" administrador a los modelos de proxy. Esto asegurará que Dog.objects siempre busque Animal instancias con type="dog" y Cat.objects obtendrá Animal instancias con type="cat".

class TypeAwareManager(models.Manager): 
    def __init__(self, type, *args, **kwargs): 
     super(TypeAwareManager, self).__init__(*args, **kwargs) 
     self.type = type 

    def get_query_set(self): 
     return super(TypeAwareManager, self).get_query_set().filter(
       type = self.type) 

class Dog(Animal): 
    objects = TypeAwareManager('dog') 
    ... 

class Cat(Animal): 
    objects = TypeAwareManager('cat') 
    ... 

segundo lugar, ir a buscar instancias de subclases separado. A continuación, puede combinarlos antes de operar en ellos. He usado itertools.chain para combinar dos Querysets.

from itertools import chain 
q1 = Cat.objects.all() # [<Cat: Daisy [cat]>] 

q2 = Dog.objects.all() # [<Dog: Bruno [dog]>] 

for each in chain(q1, q2): 
    each.make_noise() 

# Meow Meow 
# Woof Woof 
+0

Soy consciente de que voy contra el grano de Django. Hago esto porque Django no me deja hacer lo que quiero, que es obtener una lista de objetos que están almacenados en la misma tabla pero que tienen diferentes propiedades sin encadenar los resultados. Creé un administrador de tipos de conocimiento, pero a nivel de superclase y ahora solo necesito 'convertir' las instancias de objetos de superclase devueltos para que sean los objetos de la clase de proxy. ¿Hay alguna manera de hacer esto? –

+0

En realidad, ya he hecho esto, pero actualmente estoy haciendo una llamada a la base de datos de la siguiente manera: animal_proxy = Cat.objects.get (id = animal.id) Quiero algo como animal_proxy = (Cat) animal. Sé que tiene que haber un truco de pitón que pueda hacer esto por mí. –

+0

@Bubba: vea esta pregunta. Las respuestas pueden ser de su interés. http://stackoverflow.com/questions/2218867/right-way-to-return-proxy-model-instance-from-a-base-model-instance-in-django –

2

que haría:

def reklass_model(model_instance, model_subklass): 

    fields = model_instance._meta.get_all_field_names() 
    kwargs = {} 
    for field_name in fields: 
     try: 
      kwargs[field_name] = getattr(model_instance, field_name) 
     except ValueError as e: 
      #needed for ManyToManyField for not already saved instances 
      pass 

    return model_subklass(**kwargs) 

animals = Animal.objects.all() 
for animal in animals: 
    if (animal.type == "cat"): 
     animal_proxy = reklass_model(animal, Cat) 
    elif (animal.type == "dog"): 
     animal_proxy = reklass_model(animal, Cat) 
    animal_proxy.make_noise() 

# Meow Meow 
# Woof Woof 

no he probado con "zoológico";) pero con mis propios modelos parece funcionar.

Cuestiones relacionadas