3

我正在尝试在 django 中建模树结构。这是我所拥有的简化版本:

from django.db import models

class Node(models.Model):
    parent = models.ForeignKey("Node", null=True)
    name = models.CharField(max_length=20)

    def child_cnt(self):
        return self.node_set.count()

    def __unicode__(self):
        return self.name

到目前为止,一切都很好。有用。但是,如果我现在开始创建这样的层次结构:

from ....models import Node
root = Node()
root.name = "ROOT"
root.parent = None
root.save()

n = Node()
print n.child_cnt()
>> 1
print n.node_set.all()
[<Node: ROOT>]

那么根节点作为一个子节点在里面做n什么呢?我怎样才能避免这种情况?

一旦我打电话,问题就消失了,但是在管理站点内n.save()看到一个用 1 初始化的节点有点讨厌。child_cnt

4

2 回答 2

1

我知道这听起来很疯狂,但我花了几分钟试图解决你的问题,但我尝试过的任何尝试都没有奏效。无论如何,对于Tree ForeignKey,我在网上找到了另一个解决方案,这是一个完整的库,负责处理这种类型的Key,https://github.com/django-mptt/django-mptt 你可以试试,它可能适合你。我讨厌不得不为这么小的东西添加一个库,但是我找不到更好的东西。

此外,如果您不想导入整个库,您可以只将 TreeForeignKey 带入您的代码。

于 2012-06-11T14:43:21.323 回答
1

好的,经过一些研究 - 以下是结果:

首先,请注意 - 当使用具有递归关系的 ForeignKey 时,您应该使用“self”而不是类名: https ://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models .外键

然后 - ForeignKey 是 OneToOne 关系。在枚举其父节点时枚举节点子节点是不正确的......回到问题 - 当你调用 node_set.all() - 这似乎是作为 Node.objects.all() 执行的,这就是它显示的原因新创建的节点实例的项目(未保存在数据库中)。实际上 node.node_set 不能在这里用于获取节点的外键。为了有几个孩子到一个节点 - 你必须使用 ManyToManyField,例如:

children = models.ManyToManyField('self', null=True)

然后使用以下命令调用它:

node.children.all() # for all children

或者

node.children.count()

编辑

简要分析:

class A(model):
    parent = ForeignKey(B)

然后

a = A()
b = B()
b.parent_set.all() 

将返回所有以 B 作为父级的 A,或所有具有 parent_id = b.id 的 A。在你的情况下,你实际上有:

a = A()
b = A()
b.parent_set.all() 

将返回所有具有 b(==a) 作为父级的 A,在这种情况下 a.parent_id = b.id,但 b.id 为 None(未保存),因此您将获得所有具有 parent_id = 的节点(b)没有任何。

事实上,这种行为对于非递归关系也是一样的。在第一个示例中,使用 parent=None 保存 A(),您将在 b.parent_set.all() 中为所有未保存的 B 获取它。

于 2012-06-11T14:58:03.357 回答