在 Django 中创建无限的论坛层次结构 [英] Creating an unlimited forum hierarchy in Django

查看:31
本文介绍了在 Django 中创建无限的论坛层次结构的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为我希望在 Django 中创建的论坛设计模型.

到目前为止我有:

<块引用>

类论坛(models.Model):name = models.CharField(max_length=255)弹头=models.SlugField(max_length=150)描述 = 模型.TextField()def __unicode__(self):返回 self.name类子论坛(模型.模型):parent_forum = models.ForeignKey('论坛',related_name='forums')parent = models.ForeignKey('self', blank=True, null=True,related_name='children')名称 = 模型.CharField(max_length=300)弹头=models.SlugField(max_length=150)描述 = 模型.TextField()def __unicode__(self):如果 self.parent:返回 u'%s: %s - %s' % (self.parent_forum.name,self.parent.name,自己的名字)return u'%s: %s' % (self.parent_forum.name, self.name)

这在大多数情况下都有效,因为我可以选择父类别,尽管我不确定如何选择孩子父母的父母.例如,如果我有以下内容:

祖父母 ->父级 ->孩子

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

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

最后,SubForum 模型中的 __unicode__ 函数允许我打印父级,但是祖父级呢.我可以让 __unicode__ 打印所有祖先吗?

谢谢.

解决方案

使用父子关系

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

如果您只需要执行广度优先搜索 (BFS),即选择只选择一个论坛的直系父母或孩子,像你写的那样的代码和 Django ORM 会很棒.

您甚至可以获得孩子的祖父母,但是一旦 ORM 命中数据库,它将需要大量的 SQL SELECTJOIN 操作,这可能是慢的.

使用单一模型

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

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

n = 2 # 祖父母节点 = Model.objects.get(pk=1)而 n:如果 node.parent:节点 = node.parent# 在循环结束时`node` 指向祖父母

在SQL数据库中建模树结构

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

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

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

其他:不错的文章分层数据数据库设计.

I'm trying to design models for a forum I wish to create in Django.

So far I have:

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)

This works for the most part as I am able to choose a parent category although I am not sure how to select parent of a child's parent. For example if I had the following:

Grandparent -> Parent -> Child

How would I select Grandparent from Child?

This kind of hierarchy also makes the Django admin rather messy as it doesn't cascade in an orderly fashion. Do I have to build the entire admin from scratch in order to organise this into a usable interface?

Lastly the __unicode__ function in the SubForum model allows me to print the parent but what about a grandparent. Can I get __unicode__ to print all ancestors?

Thanks.

解决方案

Using parent/child relationship

While it is true that you could use two models with parent/child relationship to represent you forum hierarchy, due to the fact that the models are stored in relational SQL database you have to think first how you are going to use those models so you can in turn properly model them.

If you will only every need to do breadth-first search (BFS), that is select only immediate parents or children of a single forum, code like you wrote it and Django ORM will be great.

You could even get the grandparent of the child but it will require a lot of SQL SELECT and JOIN operations once the ORM hits the database, which could potentially be rather slow.

Using a single model

So while your model is ok, it's not really suitable for your requirements, or more specifically selecting nodes far up/down the hierarchy starting with the random node (grandparents of a child).

What you want to do is to build a simple N-ary tree data structure, or in other words, a hierarchy and traverse it. You don't really need two models for this, only one models with relationship to itself would suffice (I've called it Node for example). To get a N-th parent in this model you would simply loop n times each time following your relationship (this is basically a 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

Modeling tree structure in SQL database

There are potentially number of ways to implement trees in a SQL database but in your case I would suggest using MPTT, over lets say adjacency list model to build it. Both are techniques for easy manipulation and storage of such structures. MPTT will require more writes to the database in order to add/move nodes around the tree but to select partial tree with random root (child) is super easy since you only need to filter on two integer fields.

With adjacency lists you could potentially update the tree with fewer writes, but you would need to do much more operations to select partial tree starting from random root.

As for implementation of MPTT as a Django application try django-mptt.

Misc: nice article hierarchical data database design.

这篇关于在 Django 中创建无限的论坛层次结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆