4

我正在使用 Django 编写博客应用程序,并且正在尝试实现分层类别结构。每个类别都有一个“父”外键,指向同一个类别模型。我想允许管理员添加类别,并且我希望界面允许他们选择类别的父类别。但是,我想避免我是我自己的祖父的情况,所以我想将可用的类别选择限制为那些没有作为祖先的类别。

现在,我正在从视图中控制它:

parent_candidates = list(Category.objects.all())
pruned_parent_list = [cat for cat in parent_candidates if instance.id not in cat.getHierarchy()]

其中 instance 是正在编辑的类别,而 getHierarchy() 是获取祖先 ID 列表的方法。

这种方法存在许多问题。特别是,它使用额外的数据库命中来获取所有类别的列表,并且当我真的只想指定一个小部件时,它使我通过循环 pruned_pa​​rent_list 来将选择机制写入我的模板以获取选项。

有没有更好的方法来做到这一点?我知道我可以在后端添加自定义验证来防止这种情况,但为什么要让用户选择呢?

4

5 回答 5

1

我不得不处理 SQL 上的任意深度类别,它似乎不太适合以正常形式存储这种类型的数据,因为嵌套查询和/或多个 JOIN 往往会很快变得丑陋

这几乎是我会采用一种不恰当的解决方案的唯一情况,即以字符串形式存储类别,子类别由分隔符分隔。它使数据库查询和其他操作变得更加简单。

类别表看起来像这样:

id    name
1     Internet
2     Internet/Google
3     Internet/Yahoo
4     Offline
5     Offline/MS Office/MS Excel
6     Offline/Openoffice

另一个解决方案是,根据您的预期用途,您可以在类别列表中实现二叉树。这允许优雅地选择类别树和父/子关系。然而,它的局限性在于,在插入新类别时,可能必须重新计算整个树,并且提前知道树的大致大小是有用的。

无论如何,SQL 中的分层数据本身并不是微不足道的,因此,无论您做什么,您都可能需要进行一些自定义编码。

于 2008-12-31T08:20:45.420 回答
1

看看django-treebeard应用程序。

于 2009-01-02T13:09:01.300 回答
0

“有没有更好的方法来做到这一点?” 并不真地。层次结构在关系模型中很难。除了完全放弃 SQL 之外,没有什么比这更容易了。

“通过循环 pruned_pa​​rent_list 将选择机制写入我的模板以获取选项” - 可能不是最佳的。在您看来,这应该发生。

于 2008-12-30T19:20:22.453 回答
0

如果我正确理解您的困境,那么问题本身就在于您处理哪些类别可以是父母,哪些不能是父母的方式。避免这些问题的一种选择是实际限制可以成为父母的类别的级别。例如,假设您有以下类别:

  • 互联网
    • 谷歌
    • 雅虎
  • 离线
    • 微软Office
    • 开发办公室

我通常处理这个问题的方式显然是在类别表上有一个 parent_id FK。对于根元素(Internet、Offline),parent_id 将为 0。因此,当您在视图中尝试检索下拉列表的“父类别”时,您需要确定它们可以嵌套多远。我主要将其限制在第一级,因此要选择要在下拉列表中显示的类别,您可以执行以下操作:

parents = Category.objects.filter(parent_id=0)

现在显然,这在一定程度上限制了方法,但是您可以增加您想要包含的级别并在模板中为下拉菜单制定某种视觉识别系统(包括层次结构中每个级别的额外空格或破折号或其他东西)。

无论如何,对冗长的回复感到抱歉,希望这能在一定程度上解决您的问题。

于 2008-12-30T19:42:19.180 回答
0

我不确定这是否更好(交互方式或其他方式)但是......

您可以在保存时检查层次结构完整性,并在必要时引发错误。

理想情况下,对于这种数据类型,我希望在旁边看到一棵实例树。或者至少是对象详细视图上的完整祖先。在这两种情况下,您已经完成了提到数据库的额外行程。

于 2008-12-30T20:36:29.833 回答