如何使用 django 表单/模型来表示字段之间的选择?

Posted

技术标签:

【中文标题】如何使用 django 表单/模型来表示字段之间的选择?【英文标题】:How can I use django forms/models to represent choices between fields? 【发布时间】:2010-10-05 04:29:44 【问题描述】:

如何在模型字段中使用布尔选项来启用/禁用其他字段。如果布尔值为真/假,我希望它启用/禁用其他模型字段。有没有办法使用 django 模型/表单/小部件本地表达这些关系?我一直在编写自定义模板来模拟这些关系,但是如果没有特殊的模板,我想不出一种在 django 中表示它们的好方法。

例如:

类PointInTime(模型。模型): is_absolute_time = models.BooleanField() absolute_time = models.DateTimeField() is_relative_time = models.BooleanField() days_before = models.IntegerField()

因此,如果 is_absolute_time 为 True,我希望 absolute_time 条目可在 GUI 中编辑,而 days_before 条目灰显且不可编辑。如果“is_relative_time”标志为 True,我希望 absolute_time 条目变灰,并且 days_before 值可编辑。因此 is_absolute_time 和 is_relative_time 将是 GUI 中同一组中的单选按钮,并且它们的两个对应字段仅在选择它们的单选按钮时才可编辑。这在自定义模板中很容易做到,但是有没有办法在 django 中使用模型/表单来原生显示这种关系?

【问题讨论】:

【参考方案1】:

澄清您所说的“本机显示这种关系”的含义并清楚地考虑关注点分离会有所帮助。

如果您只想根据另一个字段的值“变灰”或禁用某个字段,这纯粹是一个演示/UI 问题,因此模板(和/或 javascript)是处理的合适位置它。

如果您想验证提交的数据是否内部一致(即,如果 is_absolute_time 为 True,则填写 absolute_time 等),这是一个表单验证问题。该逻辑的位置在您的 Form 或 ModelForm 对象的 clean() 方法中。

如果您想确保没有任何 PointInTime 模型可以在没有内部一致性的情况下保存到数据库中,那就是数据层问题。这样做的地方是在模型对象的自定义 save() 方法中(Django 1.2 将包含一个more extensive model validation system)。

所有这些选项都涉及编写命令式代码来执行您对这些特定字段的需要。您可能正在寻找一种在模型中以声明方式表示情况的方法,以便可以通用而不是专门编写上述所有三种情况的代码。没有内置的 Django 方法可以做到这一点,但你当然可以这样做:

class PointInTime(models.Model):
    field_dependencies = 'is_absolute_time': 'absolute_time',
                          'is_relative_time': 'days_before'
    ... fields here ...

然后您的模型 save() 代码(或您的 Form clean() 代码或您的模板)可以使用此字典来确定应启用/禁用哪些字段,具体取决于哪个字段的值。不过,这种概括几乎不值得付出努力,除非您预计需要在许多不同的模型中做同样的事情。

最后,您可能需要考虑一些架构设计替代方案,以使您的数据层更好地标准化:

如果只有两个有效状态(绝对和相对),请使用单个布尔字段而不是两个。然后你避免可能的不一致(如果两个布尔值都是 False 或 True 是什么意思?)

或者通过完全消除布尔值并仅在 absolute_time/days_before 中的一个或另一个中使用 Null 值来进一步简化。

如果可能有两个以上的有效状态,请使用单个 IntegerField 或 CharField 进行选择,而不是使用两个布尔字段。原因同上,但可以容纳两个以上的选项。

由于 RelativeTime 和 AbsoluteTime 似乎不会相互共享任何数据字段,因此请考虑将它们完全拆分为单独的模型。如果您有其他模型需要 ForeignKey 到其中一个或另一个,您可以使用继承来建模(RelativeTime 和 AbsoluteTime 都继承自 PointInTime,其他模型具有指向 PointInTime 的 ForeignKey)。

【讨论】:

【参考方案2】:

我不完全确定你在用这些对象做什么,但无论用户选择哪个,你都指向一个时间点。 “5 天前”是“星期四”,反之亦然。

所以除非日期随网站滚动(例如,“5 天前”的记录仍表示星期四、明天等),这肯定只是界面问题吗?如果是这种情况,我会在你的模型中坚持使用单一的日期值,让表单和视图完成所有工作。

这解决了自动生成的管理方面的问题,因为您只需处理一个字段,但它本身不会让您在两者之间进行选择,除非您编写自己的表单小部件并覆盖 ModelAdmin 类你的模型。

如果不是这样,请忽略这个答案。

【讨论】:

相对时间将相对于其他日期时间值(今天或其他记录)滚动。因此它在数据库中的建模方式不同,我实际上将“5”存储为整数表示相对日期时间比其他日期时间早 5 天。

以上是关于如何使用 django 表单/模型来表示字段之间的选择?的主要内容,如果未能解决你的问题,请参考以下文章

Django - 如何在作为模型当前字段的模型表单上添加占位符?

如何在 django 中创建表单和模型中使用的字段的单选按钮

Django:如何更改内联表单集中的字段小部件

如何在 django 模型表单中添加自定义字段?

如何在 django 中将一个表单字段拆分为模型的多个字段?

如何使用 Django 的 HTML 表单来编辑用户配置文件的一部分。