Django: Как мне моделировать дерево разнородных типов данных? - PullRequest
5 голосов
/ 14 ноября 2008

Мне нужно сохранить древовидную структуру данных в моей базе данных, для которой я планирую использовать django-treebeard или, возможно, django-mptt . Мой источник путаницы заключается в том, что каждый узел может иметь один из трех возможных типов: корневые узлы всегда будут объектом типа A, конечные узлы - объектом типа C, а все промежуточное будет объектом типа B. Я хотел бы знать, как лучше всего смоделировать эту ситуацию.

обновление: Сначала я попробовал наследование модели, и я думаю, что это может быть лучшим способом. К сожалению, публичный API django-treebeard не предназначен для этого. Я закончил тем, что заставил его работать с GenericForeignKey. Большое спасибо за ответы.

Ответы [ 4 ]

3 голосов
/ 15 ноября 2008

Как насчет использования родового отношения из модели, которая будет содержать древовидную структуру для объекта контента для узла, который она представляет?

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

Это может привести к большому количеству запросов при извлечении объектов контента для полного дерева, но есть способов и средств для уменьшения количества требуемых запросов.

# 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 голосов
/ 15 ноября 2008

Ваши три типа, вероятно, легче всего обрабатывать как ассоциации FK с фундаментальным деревом.

Дерево может быть однородным - класс MyNode является прямым подклассом treebeard.Node. Ваш узел может иметь флаг (Root, Middle, Leaf) и FK для A, B или C. Это дает вам некоторую SQL-подобную гибкость при запросе экземпляра MyNode.

Это позволяет вашему дереву расти. Узел может начинаться с типа C (лист) и затем переходить в тип B (промежуточный). Вы меняете статус и меняете FK.

Альтернатива немного сложнее.

class MyA( treebeard.Node ):
    pass

class MyB( treebeard.Node ):
    pass

class MyC( treebeard.Node ):
    pass

В этом случае вы не можете «трансформировать» узел. Когда узел запускается как MyC и получает дочерние элементы, необходимо удалить исходный экземпляр MyC и заменить его версией MyB, в которой новый узел является дочерним. Это не невозможно, но это может быть больно.

1 голос
/ 03 декабря 2009

Что ж, для вас уже многое сделано, в некотором смысле, потому что корни, листья и другие уже изначально определены в API дерева. Вы можете вызывать is_root () и is_leaf () на отдельных узлах, чтобы различать их.

Листья и промежуточные объекты могут относиться к объектам одного и того же типа и содержать данные одного и того же типа в зависимости от способа интерпретации и использования данных приложением в зависимости от тестирования is_leaf ().

Корни являются чем-то особенным ... они могут содержать информацию, относящуюся ко всему дереву, и вам может понадобиться простой способ поиска определенных корней и хранения дополнительных данных. Вы можете сделать это с моделью, которая имеет отношение один к одному с корневым узлом (возможно, с перегруженным методом сохранения и проверкой, чтобы убедиться, что узел указывает на is_root () перед разрешением сохранения).

В целом, я хочу сказать, что вам не нужно слишком увлекаться, чтобы делать то, что вы хотите. Различие, которое вы проводите, уже заложено в концепции дерева и его API, и вы, вероятно, могли бы реализовать различное поведение с одними и теми же базовыми данными, проверив контекст узла.

0 голосов
/ 18 декабря 2010

Если древовидная структура является неотъемлемой частью вашего приложения, рассмотрите возможность использования чего-либо другого, кроме реляционной базы данных. Может быть neo4j?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...