5 Stimmen

Django: Wie modelliere ich einen Baum mit heterogenen Datentypen?

Ich muss eine Baumdatenstruktur in meiner Datenbank speichern, für die ich plane, Folgendes zu verwenden django-treebeard oder möglicherweise django-mptt . Was mich verwirrt, ist die Tatsache, dass jeder Knoten einer von drei verschiedenen möglichen Typen sein kann: Die Wurzelknoten sind immer vom Typ A, die Blattknoten vom Typ C und alles dazwischen ist vom Typ B. Ich würde gerne wissen, wie ich diese Situation am besten modellieren kann.

aktualisieren: Ich habe zunächst versucht, Modellvererbung, und ich denke, dass dies der beste Weg zu gehen sein könnte. Leider ist die öffentliche API von django-treebeard nicht wirklich dafür ausgelegt, dies zu handhaben. Am Ende habe ich es mit GenericForeignKey zum Laufen gebracht. Vielen Dank für die Antworten.

3voto

S.Lott Punkte 371691

Ihre drei Typen sind wahrscheinlich am einfachsten als FK-Assoziationen mit dem Grundbaum zu behandeln.

Der Baum kann homogen sein - Klasse MyNode ist eine direkte Unterklasse von treebeard.Node . Ihr Knoten kann ein Flag (Root, Middle, Leaf) und FK's für A oder B oder C haben. Dies erlaubt Ihnen eine SQL-ähnliche Flexibilität bei der Abfrage der MyNode-Instanz.

So kann Ihr Baum wachsen. Ein Knoten kann als Typ C (Blatt) beginnen und sich dann in einen Typ B (Zwischenstufe) verwandeln. Sie ändern den Status und ändern die FKs.

Die Alternative ist ein wenig 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 und Kinder bekommt, müssen Sie das Original entfernen MyC Instanz, und ersetzen Sie sie durch eine MyB Version, die einen neuen Knoten als Kind hat. Das ist nicht unmöglich, kann aber mühsam sein.

3voto

Jonny Buchanan Punkte 60128

Wie wäre es mit der Verwendung eines generische Beziehung von dem Modell, das die Baumstruktur enthält, zu dem Inhaltsobjekt für den Knoten, den es repräsentiert?

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 zu einer Vielzahl von Abfragen führen, wenn Inhaltsobjekte für den gesamten Baum abgerufen werden, aber es gibt Mittel und Wege die Anzahl der erforderlichen Abfragen zu verringern.

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

1voto

Stephen DeGrace Punkte 11

Nun, in gewisser Weise wird bereits viel für Sie getan, denn Wurzeln, Blätter und andere sind bereits von der Baum-API identifiziert. Sie können is_root() und is_leaf() für einzelne Knoten aufrufen, um sie zu unterscheiden.

Leaves und In-betweens können die gleiche Art von Entität sein und die gleiche Art von Daten enthalten, wobei die Art und Weise, wie die Daten von der Anwendung interpretiert und verwendet werden, von der Prüfung is_leaf() abhängt.

Wurzeln sind etwas Besonderes... sie könnten Informationen enthalten, die für den gesamten Baum relevant sind, und man könnte eine einfache Möglichkeit haben, bestimmte Wurzeln nachzuschlagen und zusätzliche Daten zu speichern. Man könnte dies mit einem Modell tun, das eine Eins-zu-Eins-Beziehung zu einem Root-Knoten hat (vielleicht mit der überladenen save-Methode, die prüft, ob der Knoten, auf den sie zeigt, is_root() ist, bevor sie das Speichern erlaubt).

Was ich damit sagen will, ist, dass Sie sich nicht unbedingt etwas einfallen lassen müssen, um das zu erreichen, was Sie wollen. Die Unterscheidung, die Sie machen, ist bereits im Konzept des Baums und seiner API gekapselt, und Sie könnten wahrscheinlich ein anderes Verhalten mit den gleichen Basisdaten implementieren, indem Sie den Kontext des Knotens überprüfen.

0voto

Emil Stenström Punkte 11959

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X