2011-09-23 24 views
7

Mi modelo Discount describe los campos comunes para todos los tipos de descuentos en el sistema. Tengo algunos modelos proxy que describen el algoritmo concreto para calcular el total. La clase base Discount tiene un campo de miembro denominado type, que es una cadena que identifica su tipo y su clase relacionada.polimorfismo modelo django con herencia proxy

class Discount(models.Model): 
    TYPE_CHOICES = (
    ('V', 'Value'), 
    ('P', 'Percentage'), 
) 

    name = models.CharField(max_length=32) 
    code = models.CharField(max_length=32) 
    quantity = models.PositiveIntegerField() 
    value = models.DecimalField(max_digits=4, decimal_places=2) 
    type = models.CharField(max_length=1, choices=TYPE_CHOICES) 

    def __unicode__(self): 
    return self.name 

    def __init__(self, *args, **kwargs): 
    if self.type: 
     self.__class__ = getattr(sys.modules[__name__], self.type + 'Discount') 
    super(Discount, self).__init__(*args, **kwargs) 

class ValueDiscount(Discount): 
    class Meta: 
    proxy = True 

    def total(self, total): 
    return total - self.value 

Pero sigo obteniendo una excepción de AttributeError diciendo que uno no tiene el tipo. ¿Cómo solucionar esto o hay otra forma de lograr esto?

Respuesta

11

Su método init tiene que tener este lugar:

def __init__(self, *args, **kwargs): 
    super(Discount, self).__init__(*args, **kwargs) 
    if self.type: 
     self.__class__ = getattr(sys.modules[__name__], self.type + 'Discount') 

es necesario llamar a super __init__ antes de que será capaz de acceder self.type.

Cumplir con llamar a su campo type desde type también es una función incorporada de python, aunque es posible que no tenga ningún problema.

Ver: http://docs.python.org/library/functions.html#type

+0

Gracias. Una pregunta más, ¿por qué debo llamar a super__init__ antes de acceder a las propiedades de los objetos? Pensé que es una pitón que hace que todos los miembros declarados en el objeto sean accesibles en el constructor, no en la superclase (modelos.Modelo de Django). ¿Cómo? – aambrozkiewicz

+2

Esto es porque django.db.models.Model tiene '__metaclass__ = ModelBase'. Esto significa que django usa 'ModelBase' para crear su clase de modelo en lugar del' tipo' normal. Recomiendo leer: http://stackoverflow.com/questions/100003/what-is-a-metaclass-in-python - y una vez que hayas dominado las metaclases, mira el código fuente de django. –

0

llamada super(Discount, self).__init__(*args, **kwargs) antes de hacer referencia self.type.

Cuestiones relacionadas