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

Ash*_*Ash 1 django django-templates django-models

我正在尝试为我想在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)
Run Code Online (Sandbox Code Playgroud)

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

Grandparent -> Parent -> Child
Run Code Online (Sandbox Code Playgroud)

我如何从孩子中选择祖父母?

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

最后,__unicode__SubForum模型中的函数允许我打印父级,但祖父母的情况如何.我可以__unicode__打印所有祖先吗?

谢谢.

Dav*_*cic 6

使用父/子关系

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

如果您只需要进行广度优先搜索(BFS),即只选择直接父母或单个论坛的子代,那么像您编写的代码和Django ORM将会很棒.

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

使用单一模型

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

你想要做的是建立一个简单的N元树数据结构,换句话说,一个层次结构并遍历它.你真的不需要两个模型,只有一个与自身有关系的模型就足够了(Node例如我称之为).要在此模型中获得第N个父级,您只需在每次跟随关系后循环n次(这基本上是链接列表)

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
Run Code Online (Sandbox Code Playgroud)

在SQL数据库中建模树结构

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

使用邻接列表,您可以使用较少的写入更新树,但是您需要执行更多操作以从随机根开始选择部分树.

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

杂项:好的文章分层数据数据库设计.