2010-06-24 3 views
7

Der folgende Code Abfrage gegeben:Django Modell Subklassifizieren: Erhalten Sie die Unterklasse von der übergeordneten Klasse

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() 

Ich möchte jetzt jedes BaseMedium abfragen.

b = BaseMedium.objects.all() 

Wie drucke ich alle Informationen einschließlich der Unterklassenfelder, ohne zu wissen, was der Unterklasse-Typ ist?

b[0].a würden die Informationen drucken, wenn b[0] tatsächlich zu einer A Instanz verwandt ist, aber wenn es zu B verwandt ist wäre es eine DoesNotExist Ausnahme drucken.

Dies ist sinnvoll, aber ich möchte eine gemeinsame Variable oder Methode haben, die das zugehörige Objekt zurückgibt.

Vielleicht ist mein Datenbank-Layout nicht wirklich toll, um so zu fragen, wenn ja, würde ich mich freuen, wenn Sie ein besseres Layout empfehlen würden.

Ich dachte über eine 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') 

verwenden, aber diese Lösung scheint kompliziert und ich glaube, Sie Jungs haben bessere Lösungen zu sein.

Antwort

2

Der einzige Weg, dies zu tun, ist explizit auf dem Basismodell zu speichern, welcher Typ es ist. Also haben Sie ein derived_type (oder was auch immer) Feld auf BaseMedium, und setzen Sie es auf Speichern. Dann können Sie eine get_derived_type Methode haben:

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

und so weiter.

1

Danke herr. Roseman für deine Antwort. Ich habe deine Idee ein bisschen weiterentwickelt. Hier ist, was ich kam mit:

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 

verwendet Dies ist eine Methode, mit BaseMedium.

+0

Sie sollten vorsichtig mit diesem sein. Wenn Sie 1000 Datensätze haben, die aus DB abgerufen werden sollen, wird dies in einem SELECT durchgeführt, aber dann werden 1000 einzelne Selects sein, um den Subtyp für jedes BaseMedium-Objekt zu erhalten. Jedenfalls weiß ich keine bessere Idee, wie man das macht. Ich benutze etwas similar, das viele zusätzliche db-Abfragen erzeugt ... – dzida

+1

schießen Sie haben Recht. Benutzerdefinierte sql könnte eine Option sein ... Die seltsame Sache ist, ich verstehe nicht, wie das ist kein allgemein bekanntes Problem mit bekannten Lösung. – rotrotrot

3

Sie sollten die Lösung posted by Carl Meyer vor einiger Zeit überprüfen. Es verwendet intern den ContentType-Ansatz, kapselt es jedoch sehr elegant.

Er verweist auch auf eine alternative und effizientere Lösung, die kein zusätzliches Feld in der Datenbank speichern muss, sondern nur für direkte untergeordnete Klassen. Wenn Sie mehrere Vererbungsebenen haben, ist die erste Lösung besser.

Verwandte Themen