2009-07-30 15 views
1

Ich habe zwei Klassen Django-Modell, das auf die ähnlich strukturiert sind folgende:Filtering Modelle mit Vererbung in Django

class Build(models.Model): 
    project = models.CharField(max_length=100) 
    ... 

class CustomBuild(Build): 
    custom_type = ... 
    ...

ich alle Builds und CustomBuilds auswählen möchten (jeweils CustomBuild hat eine Eins-zu-Eins Beziehung mit einem Build) aus der Datenbank mit einem bestimmten Projektattribut.

Ich glaube, Build.Objects.Filter (Projekt = "Myproject") wird die richtigen Objekte auswählen, aber viele von ihnen fehlen die zusätzlichen Daten (wie Custom_Type), die von einem CustomBuild-Objekt bereitgestellt werden würde. Auf der anderen Seite werden beim Filtern von CustomBuild.Objects Objekte ausgeschlossen, die keine CustomBuilds sind.

Wie kann ich das erreichen? Vielen Dank.

Antwort

1

Sie holen können Objekte mit Build.objects.filter Bauen() und die Unterklasse zugreifen, wenn Sie müssen:

qs = Build.objects.all() 
build_obj = qs[4] 
custom_build_obj = build_obj.custom_build 
custom_build_obj.custom_type = ... 
3

Es gibt ein paar Ansätze, die Sie auf den Umgang mit den QuerySet s von „Mischmodelle nehmen "dass Sie erhalten, wenn Sie diese Art von Abfrage durchführen. Vieles hängt von deinem ultimativen Ziel ab.

Der "einfache und dumme" Weg, den ich oft nutze, besteht darin, die Ergebnisse mit Utility-Funktionen zu verwalten. Wenn Sie beispielsweise das Ergebnis Build.objects.filter(project="myproject") in einer Vorlage verarbeiten möchten, können Sie benutzerdefinierte Vorlagen-Tags oder Filter verwenden, um spezielle Maßnahmen zu ergreifen. Es sei angenommen, in dem unten stehenden Code build_objects enthält das Ergebnis des Filters():

{% for build in build_objects %} 
    {% if build|is_custom_build %} 
     <p>This is a custom build of custom type {{ build.custom_build.custom_type }}!</p> 
    {% endif %} 
    <p>This is a custom build OR a standard build</p> 
{% endfor %} 

Das offensichtliche Problem hier ist, wenn Sie zahlreiche Unterklassen haben, schreiben Template Filter unpraktisch sein kann oder langweilig wachsen. Meiner Erfahrung nach habe ich jedoch in der Regel höchstens ein halbes Dutzend Unterklassen, daher ist das nicht immer ein Problem.

Sie könnten auch eine parametrisierte Filter wie so schreiben:

{% if build|is_of_buildtype:"custom_build" %} 

Mit dem Code-Filter wie folgt:

def is_of_buildtype_filter(value, arg): 
    if hasattr(value, arg): return True 
    else: return False 

Dieser Filter einfach auf das Vorhandensein des Arguments auf das als Attribut überprüft build Objekt (als value übergeben). Die Argument-Zeichenfolge sollte der Name der automatisch generierten OneToOneField sein, die Sie ermitteln möchten, in diesem Fall custom_build.

Für Ansichtscode funktionieren ähnliche Arten von Hilfsfunktionen auf die gleiche Weise, sind aber noch einfacher, da Sie keine benutzerdefinierten Filter oder Tags schreiben müssen.

Dieser Ansatz funktioniert in vielen Fällen, aber es gibt kompliziertere Szenarien, in denen es möglicherweise nicht praktikabel ist. Leider kann Django Ihnen nativ keine QuerySet liefern, die Unterklasseninstanzen enthält, wenn Sie Operationen für die Basisklasse ausführen (dh eine QuerySet, die wirklich "gemischte Modelle" enthält). Dies kann in Situationen erforderlich sein, in denen die Verarbeitung der Ergebnisse mit Hilfsfunktionen nicht möglich ist.

Ich persönlich vermeide diese Situationen völlig, normalerweise, indem ich mein Modelldesign überdenken. Aber wenn das nicht möglich ist, gibt es viele interessante Lösungsversuche, zB Inheritance MixIn. Es gibt auch einige Django-Schnipsel zum Thema.Beachten Sie jedoch, dass fast jede Lösung wie diese leistungsbegrenzt ist.

+0

Ich schätze die Zeit, die Sie in diesen Kommentar schreiben. Ich war wirklich mehr daran interessiert, wie ich das in Code statt in Templates machen konnte. Ich wünschte, ich könnte beide Antworten akzeptieren, da ich deinen hasattr-Code als nützlich empfunden habe, aber ich habe stattdessen deine Antwort hochgestuft. – titaniumdecoy