在Django中创建无限的论坛层次结构

时间:2010-07-13 21:37:06

标签: django django-models django-templates

我正在尝试为我想在Django中创建的论坛设计模型。

到目前为止,我有:

class Forum(models.Model):
    name = models.CharField(max_length=255)
    slug = models.SlugField(max_length=150)
    description = models.TextField()

    def __unicode__(self):
        return self.name

class SubForum(models.Model):
    parent_forum = models.ForeignKey('Forum', related_name='forums')
    parent = models.ForeignKey('self', blank=True, null=True, related_name='children')
    name = models.CharField(max_length=300)
    slug = models.SlugField(max_length=150)
    description = models.TextField()

    def __unicode__(self):
        if self.parent:
            return u'%s: %s - %s' % (self.parent_forum.name,
                                     self.parent.name,
                                     self.name)
        return u'%s: %s' % (self.parent_forum.name, self.name)

这在很大程度上起作用,因为我能够选择父类别,虽然我不知道如何选择孩子父母的父母。例如,如果我有以下内容:

Grandparent -> Parent -> Child

如何从儿童中选择祖父母?

这种层次结构也使得Django管理员相当混乱,因为它没有以有序的方式级联。我是否必须从头开始构建整个管理员才能将其组织成可用的界面?

最后,SubForum模型中的__unicode__函数允许我打印父级,但是祖父母也是如此。我可以__unicode__打印所有祖先吗?

感谢。

2 个答案:

答案 0 :(得分:6)

使用父/子关系

虽然您可以使用两个带有父/子关系的模型来表示您的论坛层次结构,但由于模型存储在关系SQL数据库中,您必须先考虑如何您将使用这些模型,以便您可以正确地建模它们。

如果你只需要做breadth-first search (BFS),那就是选择只有一个论坛的直接父母或孩子,代码就像你写的那样,Django ORM会很棒。< / p>

你甚至可以得到孩子的祖父母,但是一旦ORM命中数据库就需要大量的SQL SELECTJOIN操作,这可能会相当慢。

使用单一模型

因此,虽然您的模型没问题,但它并不适合您的要求,或者更具体地从随机节点(孩子的祖父母)开始,在层次结构中选择nodes远远/向下。

您要做的是构建一个简单的N-ary树数据结构,换句话说,构建一个层次结构traverse。你真的不需要两个模型,只有一个与自身有关系的模型就足够了(我称之为Node)。要在此模型中获得第N个父级,您只需在每次关系后循环n次(这基本上是linked-list

n = 2 # Grandparent
node = Model.objects.get(pk=1)
while n: 
   if node.parent:
      node = node.parent
# At the end of the loop `node` points to the grandparent

在SQL数据库中建模树结构

在SQL数据库中实现树的方法有多种,但在我的情况下,我建议使用MPTT,然后让adjacency list模型来构建它。两者都是易于操纵和存储这种结构的技术。 MPTT将需要更多写入数据库以便在树周围添加/移动节点,但选择具有随机根(子)的部分树非常容易,因为您只需要对两个整数字段进行过滤。

使用adjacency lists,您可能会使用较少的写入更新树,但是您需要执行更多操作以从随机根开始选择部分树。

对于作为Django应用程序的MPTT的实现,请尝试django-mptt

杂项:好文章hierarchical data database设计。

答案 1 :(得分:0)

我只想创建一个论坛模型,可以将另一个论坛作为其父级,或者具有空父级。然后,如果你想打印出所有父母,你可以像这个伪代码一样使用while循环:

heirarchy = ""
f = this forum model
while f.parent is not null:
   heirarchy.append(f.parent.name)
   f = f.parent

回答你问题的另一部分,为了在知道父ID的同时选择一个孩子,你会像这样查询Django的对象结构:

Forum.objects.filter(parent=PARENT_ID)

并且为了得到孩子的祖父母,你会这样做:

forum_object.parent.parent