Django中的ForeignKey表单限制

时间:2008-12-30 19:04:16

标签: python django django-forms

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

现在,我从视图中控制了这个:

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来获取选项,从而将选择机制写入我的模板,当我真的只是指定一个小部件时。

有没有更好的方法呢?我知道我可以在后端添加自定义验证以防止这种情况,但为什么要为用户提供选项?

5 个答案:

答案 0 :(得分: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中的分层数据本身并不容易,因此,无论你做什么,你都可能需要做一些自定义编码。

答案 1 :(得分:1)

查看django-treebeard应用

答案 2 :(得分:0)

“还有更好的办法吗?”并不是的。层次结构在关系模型中很难实现。除了完全放弃SQL之外,没有比这更容易了。

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

答案 3 :(得分:0)

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

  • 因特网
    • 谷歌
    • 雅虎
  • 离线
    • MS Office
    • OpenOffice的

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

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

现在显然,这有点限制了这种方法,但你可以增加你想要包含的级别,并在模板中为下拉列表设计某种视觉识别系统(包括每个级别的额外空格或破折号)等级或某事)。

无论如何,对于长时间的回复感到抱歉,希望这有点解决了你的问题。

答案 4 :(得分:0)

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

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

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