5

Ich muss eine Baumdatenstruktur in meiner Datenbank speichern, für die ich mit django-treebeard oder möglicherweise django-mptt planen. Meine Quelle der Verwirrung ist, dass jeder Knoten einer von drei verschiedenen möglichen Typen sein kann: Wurzelknoten sind immer eine Entität vom Typ A, Blattknoten eine Entität vom Typ C und alles dazwischen ist eine Entität vom Typ B. Ich würde gerne wissen, wie diese Situation am besten modelliert werden kann.Django: Wie modelliere ich eine Struktur heterogener Datentypen?

Update: Ich versuchte zuerst Modellvererbung, und ich denke, dass dies der beste Weg sein könnte. Leider ist die öffentliche API von django-treebart nicht dafür ausgelegt. Ich habe es am Ende mit GenericForeignKey arbeiten lassen. Vielen Dank für die Antworten.

Antwort

3

Wie wäre es mit einem generic relation aus dem Modell, das die Baumstruktur an das Inhaltsobjekt für den Knoten hält, den es darstellt?

from django.db import models 
from django.contrib.contenttypes.models import ContentType 
from django.contrib.contenttypes import generic 

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

Dies könnte möglicherweise in einer Menge von Anfragen führen, wenn Content-Objekte für den vollständigen Baum abrufen, aber es gibt ways and means die erforderlich, um die Anzahl der Abfragen zu reduzieren.

# Assuming mptt, as I'm not familiar with treebeard's API 

# 1 query to retrieve the tree 
tree = list(Node.tree.all()) 

# 4 queries to retrieve and cache all ContentType, A, B and C instances, respectively 
populate_content_object_caches(tree) 
3

Ihre drei Typen werden wahrscheinlich am einfachsten als FK-Assoziationen mit dem Grundbaum behandelt. Der Baum kann homogen sein - Klasse MyNode ist eine direkte Unterklasse von treebeard.Node. Ihr Knoten kann ein Flag (Root, Middle, Leaf) und FKs für A oder B oder C haben. Dies ermöglicht Ihnen eine SQL-ähnliche Flexibilität bei der Abfrage von MyNode-Instanzen.

Dies ermöglicht Ihrem Baum zu wachsen. Ein Knoten kann als Typ C (Blatt) beginnen und dann zu einem Typ B (intermediär) morphen. Sie ändern den Status und ändern die FKs.

Die Alternative ist ein bisschen komplexer.

class MyA(treebeard.Node): 
    pass 

class MyB(treebeard.Node): 
    pass 

class MyC(treebeard.Node): 
    pass 

In diesem Fall können Sie einen Knoten nicht "morphen". Wenn ein Knoten als MyC gestartet wird und untergeordnete Objekte erhält, müssen Sie die ursprüngliche MyC-Instanz entfernen und sie durch eine MyB-Version ersetzen, die einen neuen Knoten als untergeordneten Knoten hat. Das ist nicht unmöglich, aber es kann schmerzhaft sein.

1

Nun wird viel für Sie bereits getan, in einer Art und Weise, denn Wurzeln, Blätter und andere sind bereits von Natur aus durch den Baum API identifiziert. Sie können is_root() und is_leaf() auf einzelnen Knoten aufrufen, um sie zu unterscheiden.

Blätter und Dazwischen können den gleichen Entitätstyp sein und den gleichen Datentyp enthalten, wobei die Art, wie die Daten interpretiert und von der Anwendung verwendet werden, vom Test is_leaf() abhängt.

Wurzeln sind etwas Besonderes ... sie könnten Informationen über den gesamten Stammbaum speichern wollen, und Sie möchten vielleicht einen einfachen Weg, bestimmte Wurzeln nachzuschlagen und zusätzliche Daten zu speichern. Sie können dies mit einem Modell tun, das eine Eins-zu-Eins-Beziehung mit einem Wurzelknoten hat (vielleicht mit der überladenen Speichermethode und der Bestätigung, dass der Knoten auf is_root() verweist, bevor das Speichern zugelassen wird).

Mein Punkt insgesamt ist, dass Sie nicht sehr viel Phantasie haben müssen, um zu tun, was Sie wollen. Die Unterscheidung, die Sie treffen, ist bereits im Konzept des Baums und seiner API eingekapselt und Sie könnten wahrscheinlich ein anderes Verhalten mit den gleichen grundlegenden Daten implementieren, indem Sie den Kontext des Knotens überprüfen.

0

Wenn eine Baumstruktur ein integraler Bestandteil Ihrer Anwendung ist, sollten Sie eine andere als eine relationale Datenbank verwenden. Vielleicht neo4j?

Verwandte Themen