database - Django: ¿cómo puedo modelar un árbol de tipos de datos heterogéneos?
database-design django-models (4)
¿Qué hay de usar una relación genérica del modelo que mantendrá la estructura de árbol para 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 generar muchas consultas al recuperar objetos de contenido para el árbol completo, pero hay formas y medios de reducir el número de consultas requeridas.
# 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)
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.
actualización: primero probé 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.
Sus tres tipos son probablemente más fáciles de manejar como asociaciones de 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 tu á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 puedes "transformar" un nodo. Cuando un nodo comienza como MyC
y obtiene hijos, debe eliminar la instancia MyC
original y reemplazarla con una versión MyB
que tenga un nuevo nodo como elemento secundario. Esto no es imposible, pero puede ser doloroso.
Bueno, ya se ha hecho mucho por ti, porque las raíces, las hojas y otras ya están identificadas inherentemente 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).
En general, mi punto es que tal vez no necesites hacerte el lujo de hacer lo que quieres. 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.
Si la estructura de un árbol es una parte integral de su aplicación, considere usar algo más que una base de datos relacional. ¿Tal vez neo4j?