【问题标题】:Creating an unlimited forum hierarchy in Django在 Django 中创建无限的论坛层次结构
【发布时间】:2011-03-15 13:55:38
【问题描述】:

我正在尝试为希望在 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__ 打印所有祖先吗?

谢谢。

【问题讨论】:

  • 为什么有SubForum?为什么不把parent 字段放在Forum 中?您仍然可以通过Forum.objects.filter(parent=None) 轻松获取所有顶级论坛的列表。
  • 但是如果我在Forum 中有一个名为SubForum 的字段和parent 字段,我可以选择所有知道顶层名称的Forums 孩子吗?或者我会获取所有ForumSubForum 条目,然后在查询之后安排它们?

标签: django django-models django-templates


【解决方案1】:

使用父/子关系

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

如果你只需要做breadth-first search (BFS),也就是选择一个论坛的直系父母或孩子,你写的代码和Django ORM会很棒。

您甚至可以获取孩子的祖父母,但一旦 ORM 访问数据库,它将需要大量 SQL SELECTJOIN 操作,这可能会相当慢。

使用单个模型

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

您要做的是构建一个简单的 N 叉树数据结构,或者换句话说,一个层次结构和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,您可能会使用更少的写入来更新树,但您需要执行更多操作才能从随机根开始选择部分树。

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

杂项:不错的文章hierarchical data database 设计。

【讨论】:

  • 我在研究标记系统时阅读了那篇文章。我希望我不必过多地偏离 django.core。感谢您的回答,值得考虑,但我不认为邻接列表的缺陷是一个大问题。在任何情况下都不会超过 100 个论坛,并且那些对 JOIN 查询征税的可以保存在缓存中。你不觉得吗?
  • @Anarchist 好吧,只是 MPTT 更容易选择,邻接更容易更新,我猜你会做更多的选择和更少的更新,因此推荐 MPTT,但两者都适合你很好,我怀疑你在这么小的数据集上应该有任何与速度相关的问题。
【解决方案2】:

我会简单地创建一个论坛模型,它可以有另一个论坛作为它的父级,或者有一个空父级。然后,如果您想打印出所有父母,您可以使用类似以下伪代码的 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 2022-07-27
    • 1970-01-01
    • 1970-01-01
    • 2012-03-04
    相关资源
    最近更新 更多