我正在尝试为我想在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__
打印所有祖先吗?
感谢。
答案 0 :(得分:6)
虽然您可以使用两个带有父/子关系的模型来表示您的论坛层次结构,但由于模型存储在关系SQL数据库中,您必须先考虑如何您将使用这些模型,以便您可以正确地建模它们。
如果你只需要做breadth-first search (BFS),那就是选择只有一个论坛的直接父母或孩子,代码就像你写的那样,Django ORM会很棒。< / p>
你甚至可以得到孩子的祖父母,但是一旦ORM命中数据库就需要大量的SQL SELECT
和JOIN
操作,这可能会相当慢。
因此,虽然您的模型没问题,但它并不适合您的要求,或者更具体地从随机节点(孩子的祖父母)开始,在层次结构中选择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数据库中实现树的方法有多种,但在我的情况下,我建议使用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