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

时间:2021-03-27 07:24:17

How can I use boolean choices in a model field to enable/disable other fields. If a boolean value is true/false I want it to enable/disable other model fields. Is there a way to natively express these relationships using django models/forms/widgets? I keep writing custom templates to model these relationships, but can't figure out a good way to represent them in django without a special template.

如何在模型字段中使用布尔选项来启用/禁用其他字段。如果布尔值为true / false,我希望它启用/禁用其他模型字段。有没有办法使用django models / forms / widgets本地表达这些关系?我一直在编写自定义模板来建模这些关系,但是如果没有特殊的模板,就无法找到在django中表示它们的好方法。

For example:

class PointInTime(models.Model):
    is_absolute_time = models.BooleanField()
    absolute_time = models.DateTimeField()
    is_relative_time = models.BooleanField()
    days_before = models.IntegerField()

So if the is_absolute_time is True, I want the absolute_time entry to be editable in the GUI and the days_before entry to be grayed out and not-editable. If the 'is_relative_time' flag is True, I want the absolute_time entry to be grayed out, and the days_before value to be editable. So is_absolute_time and is_relative_time would be radio buttons in the same Group in the GUI and their two corresponding fields would only be editable when their radio button is selected. This is easy to do in a customized template, but is there a way to use a model/form in django to natively show this relationship?

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

2 个解决方案

#1


It would be helpful to clarify what you mean by "natively show this relationship," and think clearly about separation of concerns.

通过“本地展示这种关系”来澄清你的意思是有帮助的,并清楚地思考关注点的分离。

If all you want is to "gray out" or disable a certain field based on the value of another field, this is purely a presentation/UI issue, so the template (and/or Javascript) is the appropriate place to handle it.

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

If you want to validate that the submitted data is internally consistent (i.e. absolute_time is filled in if is_absolute_time is True, etc), that's a form-validation issue. The place for that logic is in the clean() method of your Form or ModelForm object.

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

If you want to ensure that no PointInTime model can ever be saved to the database without being internally consistent, that's a data-layer concern. The place for that is in a custom save() method on your model object (Django 1.2 will include a more extensive model validation system).

如果要确保在没有内部一致性的情况下不能将PointInTime模型保存到数据库,那么这就是数据层问题。它的位置在模型对象的自定义save()方法中(Django 1.2将包含更广泛的模型验证系统)。

All of those options involve writing imperative code to do what you need with these specific fields. It may be that you're looking for a way to represent the situation declaratively in your model so that the code in all three of the above cases can be written generically instead of specifically. There's no built-in Django way to do this, but you could certainly do something like:

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

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

Then your model save() code (or your Form clean() code, or your template), could use this dictionary to determine which fields should be enabled/disabled depending on the value of which other one. This generalization is hardly worth the effort, though, unless you anticipate needing to do this same thing in a number of different models.

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

Lastly, a few schema design alternatives you may want to consider to get your data layer better normalized:

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

  • If there are only two valid states (absolute and relative), use a single boolean field instead of two. Then you avoid possible inconsistencies (what does it mean if both booleans are False? Or True?)

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

  • Or simplify further by eliminating the booleans entirely and just using Null values in one or the other of absolute_time/days_before.

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

  • If there might be more than two valid states, use a single IntegerField or CharField with choices instead of using two boolean fields. Same reason as above, but can accomodate more than two options.

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

  • Since a RelativeTime and an AbsoluteTime don't appear to share any data fields with each other, consider splitting them out into separate models entirely. If you have other models that need a ForeignKey to either one or the other, you could model that with inheritance (both RelativeTime and AbsoluteTime inherit from PointInTime, other models have ForeignKeys to PointInTime).

    由于RelativeTime和AbsoluteTime似乎没有彼此共享任何数据字段,因此请考虑将它们完全拆分为单独的模型。如果你有其他模型需要一个ForeignKey到一个或另一个,你可以使用继承对其进行建模(RelativeTime和AbsoluteTime都继承自PointInTime,其他模型有ForeignKeys到PointInTime)。

#2


I'm not entirely sure what you're doing with these objects but whichever the user chooses, you're pointing to a single moment in time. "5 days ago" is "Thursday" and vice-versa.

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

So unless the dates roll with the site (eg the record with "5 days ago" will still mean Thursday, tomorrow, etc), surely this is only an interface problem? If that's the case, I'd stick with a single value for the date in your Model and let the form and view do all the work.

因此,除非日期与网站滚动(例如,“5天前”的记录仍然意味着星期四,明天等),当然这只是一个界面问题?如果是这种情况,我会在模型中坚持使用单个值作为日期,并让表单和视图完成所有工作。

That solves the auto-generated Admin side of things as you'll just have one field to contend with but it won't natively give you the choice between the two unless you write your own form widget and override the ModelAdmin class for your Model.

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

If this isn't the case, please ignore this answer.

如果不是这种情况,请忽略此答案。

#1


It would be helpful to clarify what you mean by "natively show this relationship," and think clearly about separation of concerns.

通过“本地展示这种关系”来澄清你的意思是有帮助的,并清楚地思考关注点的分离。

If all you want is to "gray out" or disable a certain field based on the value of another field, this is purely a presentation/UI issue, so the template (and/or Javascript) is the appropriate place to handle it.

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

If you want to validate that the submitted data is internally consistent (i.e. absolute_time is filled in if is_absolute_time is True, etc), that's a form-validation issue. The place for that logic is in the clean() method of your Form or ModelForm object.

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

If you want to ensure that no PointInTime model can ever be saved to the database without being internally consistent, that's a data-layer concern. The place for that is in a custom save() method on your model object (Django 1.2 will include a more extensive model validation system).

如果要确保在没有内部一致性的情况下不能将PointInTime模型保存到数据库,那么这就是数据层问题。它的位置在模型对象的自定义save()方法中(Django 1.2将包含更广泛的模型验证系统)。

All of those options involve writing imperative code to do what you need with these specific fields. It may be that you're looking for a way to represent the situation declaratively in your model so that the code in all three of the above cases can be written generically instead of specifically. There's no built-in Django way to do this, but you could certainly do something like:

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

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

Then your model save() code (or your Form clean() code, or your template), could use this dictionary to determine which fields should be enabled/disabled depending on the value of which other one. This generalization is hardly worth the effort, though, unless you anticipate needing to do this same thing in a number of different models.

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

Lastly, a few schema design alternatives you may want to consider to get your data layer better normalized:

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

  • If there are only two valid states (absolute and relative), use a single boolean field instead of two. Then you avoid possible inconsistencies (what does it mean if both booleans are False? Or True?)

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

  • Or simplify further by eliminating the booleans entirely and just using Null values in one or the other of absolute_time/days_before.

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

  • If there might be more than two valid states, use a single IntegerField or CharField with choices instead of using two boolean fields. Same reason as above, but can accomodate more than two options.

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

  • Since a RelativeTime and an AbsoluteTime don't appear to share any data fields with each other, consider splitting them out into separate models entirely. If you have other models that need a ForeignKey to either one or the other, you could model that with inheritance (both RelativeTime and AbsoluteTime inherit from PointInTime, other models have ForeignKeys to PointInTime).

    由于RelativeTime和AbsoluteTime似乎没有彼此共享任何数据字段,因此请考虑将它们完全拆分为单独的模型。如果你有其他模型需要一个ForeignKey到一个或另一个,你可以使用继承对其进行建模(RelativeTime和AbsoluteTime都继承自PointInTime,其他模型有ForeignKeys到PointInTime)。

#2


I'm not entirely sure what you're doing with these objects but whichever the user chooses, you're pointing to a single moment in time. "5 days ago" is "Thursday" and vice-versa.

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

So unless the dates roll with the site (eg the record with "5 days ago" will still mean Thursday, tomorrow, etc), surely this is only an interface problem? If that's the case, I'd stick with a single value for the date in your Model and let the form and view do all the work.

因此,除非日期与网站滚动(例如,“5天前”的记录仍然意味着星期四,明天等),当然这只是一个界面问题?如果是这种情况,我会在模型中坚持使用单个值作为日期,并让表单和视图完成所有工作。

That solves the auto-generated Admin side of things as you'll just have one field to contend with but it won't natively give you the choice between the two unless you write your own form widget and override the ModelAdmin class for your Model.

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

If this isn't the case, please ignore this answer.

如果不是这种情况,请忽略此答案。