Django 中的 ForeignKey 形式限制
Posted
技术标签:
【中文标题】Django 中的 ForeignKey 形式限制【英文标题】:ForeignKey form restrictions in Django 【发布时间】:2010-09-28 21:41:50 【问题描述】:我正在使用 Django 编写博客应用程序,并且正在尝试实现分层类别结构。每个类别都有一个“父”外键,指向同一个类别模型。我想允许管理员添加类别,并且我希望界面允许他们选择类别的父类别。但是,我想避免 Im-my-own-grandpa 的情况,因此我想将可用的类别选择限制为那些没有问题的类别作为祖先的类别。
现在,我正在从视图中控制它:
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_parent_list 来将选择机制写入我的模板以获取选项,而我真的只想指定一个小部件。
有没有更好的方法来做到这一点?我知道我可以在后端添加自定义验证来防止这种情况,但为什么要让用户选择呢?
【问题讨论】:
【参考方案1】:我不得不在 SQL 上处理任意深度的类别,它似乎不太适合以正常形式存储这种类型的数据,因为嵌套查询和/或多个 JOIN 往往会变得丑陋非常 em> 很快。
这几乎是唯一一种我会采用一种不恰当的解决方案的情况,即以字符串形式存储类别,子类别由分隔符分隔。它使数据库查询和其他操作变得更加简单。
类别表看起来像这样:
id name
1 Internet
2 Internet/Google
3 Internet/Yahoo
4 Offline
5 Offline/MS Office/MS Excel
6 Offline/Openoffice
另一个解决方案是,根据您的预期用途,您可以在类别列表中实现二叉树。这允许优雅地选择类别树和父/子关系。但是,它有一个限制,即在插入新类别时,可能必须重新计算整个树,并且提前知道树的大致大小很有用。
无论如何,SQL 中的分层数据本身并不是微不足道的,因此,无论您做什么,都可能需要进行一些自定义编码。
【讨论】:
【参考方案2】:看看django-treebeard 应用程序。
【讨论】:
【参考方案3】:如果我正确理解您的困境,问题本身就在于您处理哪些类别可以是父母,哪些不能是父母的方式。避免这些问题的一种选择是实际限制可以成为父母的类别的级别。例如,假设您有以下类别:
互联网 谷歌 雅虎 离线 微软办公室 OpenOffice我通常处理这个问题的方式是我显然在类别表上有一个 parent_id FK。对于根元素(Internet、Offline),parent_id 将为 0。因此,当您在视图中尝试检索下拉列表的“父类别”时,您需要确定它们可以嵌套多远。我主要将其限制在第一级,因此要选择要在下拉列表中显示的类别,您可以执行以下操作:
parents = Category.objects.filter(parent_id=0)
现在显然,这在一定程度上限制了方法,但您可以增加您想要包含的级别,并在您的模板中为下拉菜单设计某种视觉识别系统(包括在等级制度什么的)。
无论如何,对于冗长的回复感到抱歉,希望这能在一定程度上解决您的问题。
【讨论】:
没错。将类别视为“分支类别”和“叶类别”。【参考方案4】:“有没有更好的方法来做到这一点?”并不真地。层次结构在关系模型中很难。除了完全放弃 SQL 之外,没有什么比这更容易了。
“通过循环 pruned_parent_list 将选择机制写入我的模板以获取选项”——可能不是最优的。在您看来,这应该会发生。
【讨论】:
【参考方案5】:我不确定这是否更好(交互方面或其他方面)但是...
您可以在保存时检查层次结构完整性,并在必要时引发错误。
对于这样的数据类型,我希望在旁边看到一棵实例树。或者至少是对象详细视图上的完整祖先。在这两种情况下,您都已经完成了提到的数据库的额外行程。
【讨论】:
“我知道我可以在后端添加自定义验证来防止这种情况,但为什么要让用户选择呢?”我认为重点是避免检查保存并引发异常。以上是关于Django 中的 ForeignKey 形式限制的主要内容,如果未能解决你的问题,请参考以下文章
Django:限制 models.ForeignKey 结果
复杂的django查询,获取foreignkey_set不包含满足限制的对象的对象
当我使用 Graphene 在 Django GraphQL API 中获取对象时,如何限制 ForeignKey 字段的项目数?