5

Necesito almacenar una estructura de datos de árbol en mi base de datos, para lo cual planeo usar django-treebeard o posiblemente django-mptt. Mi fuente de confusión es que cada nodo podría ser uno de tres posibles tipos diferentes: los nodos raíz siempre serán una entidad de tipo A, los nodos de hoja una entidad de tipo C, y cualquier elemento intermedio será una entidad de tipo B. Me gustaría saber la mejor manera de modelar esta situación.Django: ¿Cómo puedo modelar un árbol de tipos de datos heterogéneos?

actualización: Intenté por primera vez la herencia del modelo, y creo que este podría ser el mejor camino a seguir. Desafortunadamente, la API pública de django-treebeard no está diseñada para manejar esto. Terminé haciendo que funcionara con GenericForeignKey. Muchas gracias por las respuestas.

Respuesta

3

¿Qué le parece usar un generic relation del modelo que mantendrá la estructura de árbol en el objeto de contenido para el nodo que representa?

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

Esto podría dar lugar a una gran cantidad de consultas al recuperar objetos de contenido para el árbol completo, pero hay ways and means de reducir el número de consultas necesarias.

# 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

Sus tres tipos son probablemente más fáciles de manejar como asociaciones FK con el árbol fundamental.

El árbol puede ser homogéneo, la clase MyNode es una subclase directa de treebeard.Node. Su nodo puede tener un indicador (Root, Middle, Leaf) y FK's para A o B o C. Esto le permite cierta flexibilidad similar a SQL al consultar la instancia de MyNode.

Esto permite que su árbol crezca. Un nodo puede comenzar como un tipo C (hoja) y luego transformarse a un tipo B (intermedio). Cambia el estado y cambia los FK.

La alternativa es un poco más compleja.

class MyA(treebeard.Node): 
    pass 

class MyB(treebeard.Node): 
    pass 

class MyC(treebeard.Node): 
    pass 

En este caso, no se puede "transformar" un nodo. Cuando un nodo comienza como MyC y obtiene elementos secundarios, debe eliminar la instancia original MyC y reemplazarla por una versión MyB que tenga un nuevo nodo como elemento secundario. Esto no es imposible, pero puede ser doloroso.

1

Bueno, muchos ya está hecho para usted, en cierto modo, porque las raíces, hojas y otros son inherentemente ya identificados por la API de árbol. Puede llamar a is_root() e is_leaf() en nodos individuales para distinguirlos.

Las hojas y los intermedios pueden ser del mismo tipo de entidad y contener el mismo tipo de datos, con la forma en que la aplicación interpreta y utiliza los datos según las pruebas is_leaf().

Las raíces son algo especiales ... es posible que deseen mantener información pertinente para todo el árbol, y es posible que desee una forma simple de buscar raíces particulares y contener datos adicionales. Puede hacer esto con un modelo que tenga una relación de uno a uno con un nodo raíz (quizás con el método de guardar sobrecargado y comprobando que el nodo al que apunta is_root() antes de permitir el guardado).

Mi punto en general es que puede que no sea necesario que sea muy elegante para hacer lo que quiera. La distinción que está haciendo ya está encapsulada en el concepto del árbol y su API, y probablemente podría implementar un comportamiento diferente con los mismos datos básicos al verificar el contexto del nodo.

0

Si una estructura de árbol es una parte integral de su aplicación, considere el uso de algo más que una base de datos relacional. ¿Tal vez neo4j?

Cuestiones relacionadas