Django:如何对不同数据类型的树进行建模?

5
我需要将一个树形数据结构存储在我的数据库中,我计划使用django-treebeard或者可能是django-mptt。我的困惑在于每个节点可以是三种不同的类型之一:根节点始终是A类型实体,叶节点是C类型实体,而中间的任何节点都是B类型实体。我想知道最好的建模方法。
更新:我首先尝试了模型继承,我认为这可能是最好的方法。不幸的是,django-treebeard的公共API并没有真正设计处理这个问题。最终我通过使用GenericForeignKey解决了这个问题。非常感谢你们的回答。
4个回答

3
您的三种类型可能最容易使用基础树的FK关联来处理。
树可以是同质的--类“MyNode”是“treebeard.Node”的直接子类。您的节点可以有一个标志(Root,Middle,Leaf),以及用于A或B或C的FK。这使您可以在查询MyNode实例时获得一些类似于SQL的灵活性。
这允许您的树生长。节点可以从类型C(叶)开始,然后变成类型B(中间)。您可以更改状态并更改FK。
另一种选择比较复杂。
class MyA( treebeard.Node ):
    pass

class MyB( treebeard.Node ):
    pass

class MyC( treebeard.Node ):
    pass

在这种情况下,您不能“变形”一个节点。当一个节点作为MyC开始,并且获得子节点时,您必须删除原始的MyC实例,并用一个新的带有一个新节点作为子节点的MyB版本替换它。这并不是不可能的,但可能会很痛苦。

3
如何使用模型中的通用关系来将树形结构与节点所代表的内容对象关联起来?通用关系可以实现这一功能。
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')

这可能会导致在检索完整树的内容对象时出现大量查询,但有方法可以减少所需的查询数量。参考链接:ways and means
# 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)

1

嗯,从某种程度上说,树的API已经为您完成了很多工作,因为根、叶子和其他节点已经固有地被识别出来。您可以在单个节点上调用is_root()和is_leaf()来区分它们。

叶子和中间节点可以是相同类型的实体,并且持有相同类型的数据,应用程序如何解释和使用数据取决于测试is_leaf()的方式。

根节点有些特殊...它们可能希望持有与整个树相关的信息,并且您可能希望以一对一关系具有模型与根节点(也许重载保存方法并检查指向的节点是否为is_root()才允许保存)的简单方式查找特定的根节点并保留额外的数据。

总之,我的观点是,您可能不需要变得非常花哨才能做到想要的事情。您正在进行的区分已经封装在树及其API的概念中,您可以通过检查节点的上下文来实现相同基本数据的不同行为。


0
如果树形结构是您的应用程序的重要组成部分,请考虑使用关系型数据库之外的其他东西。也许是neo4j?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接