【问题标题】:Django MultiSelectField: Make some choices readonly when editingDjango MultiSelectField:编辑时只读一些选择
【发布时间】:2015-05-04 10:13:03
【问题描述】:

我正在使用Django MultiSelectField 来存储项目的类别。

我的要求如下:一个项目可以有一个或多个类别。最初创建项目时,用户应该能够选择选择字段中列出的任何类别。如果用户选择“不适用”,则其他类别将被禁用。

在编辑项目时,用户不能取消选择最初选择的类别,但他可以添加/选择除原始类别之外的其他类别。最初选择的类别在编辑时应该是只读的。

我的模型如下所示:

from multiselectfield import MultiSelectField
(...)

class Project(models.Model):

    CAT_0 = 0
    CAT_1 = 1
    CAT_2 = 2
    CAT_3 = 3

    PROJECT_CATEGORIES = (
        (CAT_0, _('Not Applicable')),
        (CAT_1, _('My Category 1')),
        (CAT_2, _('My Category 2')),
        (CAT_3, _('My Category 3')),
    )
    (...)
    project_categories =  MultiSelectField(choices=PROJECT_CATEGORIES, max_choices=3, default=CAT_0)

还有我的forms.py

class ProjectForm(ModelForm):

    class Meta:
        model = Project
        (...)    

    def __init__(self, *args, **kwargs):
        super(ProjectForm, self).__init__(*args, **kwargs)
        (...)

        if self.instance.pk:
            for choice in self.fields['project_categories'].choices:
                if str(choice[0]) in self.instance.project_categories:
                    #TODO: Make this choice to be readonly i.e. user should not be able to uncheck it
                else:
                    #TODO: Leave the choice as it is i.e. user can select/check it

            # This is what I had earlier, but it makes all the choices to be readonly. Not what I want
            self.fields['strategic_objectives'].widget.attrs['readonly'] = True
            self.fields['strategic_objectives'].widget.attrs['disabled'] = True

如何确保原始类别显示为只读? 这是解决方法还是 JS 会是更好的选择?

【问题讨论】:

    标签: python django


    【解决方案1】:

    在渲染之前在后端这样做有点没用,因为用户可以修改您的 html 代码并再次启用它。

    因此,使用 JS 禁用它们,然后在用户提交表单后在您的后端中,您需要检查它。

    不管怎样,前端验证由您决定,但您始终需要在后端也有它们。

    【讨论】:

      【解决方案2】:

      我遇到了和你一样的问题,在this blogpost的帮助下解决了。 基本上,有必要修改用于显示选项的小部件,以便能够将某些选项标记为禁用。

      于是我创建了一个widgets.py,内容如下:

      from django.forms import CheckboxSelectMultiple
      
      
      class CheckboxSelectMultipleWithDisabled(CheckboxSelectMultiple):
      
          def __init__(self, *args, **kwargs):
              self.disabled = kwargs.pop("disabled", set())
      
              super().__init__(*args, **kwargs)
      
          def create_option(self, *args, **kwargs):
              options_dict = super().create_option(*args, **kwargs)
      
              if options_dict["value"] in self.disabled:
                  options_dict["attrs"]["disabled"] = True
      
              return options_dict
      

      然后在表单类(ProjectForm)的构造函数中,我交换了各个字段(project_categories)的小部件,并使用了上面介绍的添加的disabled关键字参数:

          def __init__(self, *args, **kwargs):
              super(ProjectForm, self).__init__(*args, **kwargs)
      
              # fill a local 'disabled' set/list/tuple/... variable using your logic
      
              self.fields['project_categories'].widget = CheckboxSelectMultipleWithDisabled(
                  choices=self.fields['project_categories'].choices,
                  disabled=disabled
              )
      

      也不要忘记导入新的小部件以使用它:from .widgets import CheckboxSelectMultipleWithDisabled

      但 levi 发布的内容仍然正确:您可以在浏览器的 html 代码中删除 disabled 标记,并能够再次修改选择。 因此,无需任何额外验证,您就必须信任您的用户。

      this question 的回答中提出了类似的解决方案。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-05-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-20
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多