Subclasificación del modelo Django: obtenga la subclase consultando la superclase

Se da el siguiente código:

class BaseMedium(models.Model): title = models.CharField(max_length=40) slug = models.SlugField() class A(BaseMedium): url = models.URLField() class B(BaseMedium): email = models.EmailField() 

Ahora quiero consultar cada BaseMedium.

 b = BaseMedium.objects.all() 

¿Cómo imprimo toda la información, incluidos los campos de subclases, sin saber cuál es el tipo de subclase?

b[0].a imprimirá la información si b[0] está realmente relacionada con una instancia A , pero si está relacionada con B , imprimirá una Excepción DoesNotExist .

Esto tiene sentido, pero me gustaría tener una variable o método común que devuelva el objeto relacionado.

Tal vez el diseño de mi base de datos no sea realmente bueno para consultar de esa manera si así fuera, me alegraría si recomendara un mejor diseño.

Pensé en usar un GenericForeignKey

 class Generic(models.Model): basemedium = models.ForeignKey('BaseMedium') content_type = models.ForeignKey(ContentType) object_id = models.PositiveIntegerField() object = generic.GenericForeignKey('content_type', 'object_id') 

Pero esta solución parece ser complicada y creo que ustedes tienen mejores soluciones.

Debe comprobar la solución publicada por Carl Meyer hace algún tiempo. Utiliza internamente el enfoque ContentType, pero lo encapsula muy elegantemente.

También apunta a una solución alternativa y más eficiente, que no necesita almacenar un campo adicional en la base de datos, pero solo funcionará para las clases secundarias directas. Si tiene varios niveles de herencia, la primera solución es mejor.

La única forma de hacer esto es almacenar explícitamente en el modelo base qué tipo es. Por lo tanto, tenga un derived_type tipo derived_type (o cualquier otro) en BaseMedium y configúrelo para guardar. Entonces puedes tener un método get_derived_type :

 def get_derived_type(self): if self.derived_type == 'A': return self.a elif self.derived_type == 'B': return self.b 

y así.

Gracias Señor. Roseman por su respuesta. Desarrollé tu idea un poco más allá. Aquí está lo que se me ocurrió:

 def related_object(self, default_pointer_name='_ptr'): models = [A,B] #models object = None argument = '%s%s' %(self.__class__.__name__.lower(), default_pointer_name) query = { argument : self} for model in models: try: object = model.objects.get(**query) except model.DoesNotExist: pass else: return object if object == None: raise RelatedObjectException return object 

Este es un método utilizado por BaseMedium.