Django 模型表单-changed_data 中的禁用字段

问题描述 投票:0回答:2

我有一个表单基类,它检查表单正在更新的实例是否已更改,如果未更改则不保存。

这是我的自定义模型表单,我覆盖保存:

class MyModelForm(models.ModelForm):
    # .. more code here..
        def save(self, commit=True):
            if self.has_changed():
               # Won't do anything if the instance did not changed
               return self.instance
            return super(MyModelForm, self).save(commit)

我的很多表单都使用这个基类。 现在,我的其中一个表单有几个字段,我将其设置为

disabled=True
(django 1.9 +)。所以以我的一种形式:

def __init__(self, *args, **kwargs):
      ## ..code
      self.fields['address'].disabled = True

经过大量调试后,为什么

form.has_changed()
为True(因此实例被无缘无故地保存),即使我保存表单而不更改实例。我发现 django 在
changed_data
中包含禁用字段 - 这是没有意义的,因为用户无论如何都不应该更改禁用字段。

我是否遗漏了某些东西,或者它是一个错误,或者它应该如何工作? 我怎样才能在不进行太多更改的情况下解决这个问题,因为表单基类在我的代码中被大量使用。

django django-forms
2个回答
3
投票

这是 DjangoProject 的一个已知问题,票证位于 https://code.djangoproject.com/ticket/27431,相应的 PR 位于https://github.com/django/django/pull/7502。在编写此答案时,PR 已与

master
合并,因此最新版本应该已修复此问题。

解决方法如下

for form in formset:
    if form.has_changed() and form not in formset.deleted_forms:
        fields = form.changed_data
        up_f = [field for field in fields if not form.fields[field].disabled]
        if len(up_f) > 0:
            updated_data.append(form.cleaned_data)

这会导致

updated_data
拥有唯一更新且未删除的表单。


0
投票

答案中所写,

具有disabled属性的元素不会被提交或者你可以说 它们的值未发布(请参阅步骤 3 下的第二个要点 在用于构建表单数据集的 HTML 5 规范中)。

因此,您可以创建一个重复字段来显示禁用的元素,并隐藏原始字段:

class MyModelForm(forms.ModelForm):

    original_field = forms.ModelChoiceField(
        queryset = models.MyModel.objects.all(),
        label = 'My Field',
        required = True
    )

    original_field_widget = forms.ModelChoiceField(
        queryset = models.MyModel.objects.all(),
        label = 'My Field',
        required = False
    )

    class Meta:
        model = models.MyModel
        fields = ( 
            'original_field', 'original_field_widget', ...
        )

    def __init__(self, *args, **kwargs):

        super(MyModelForm, self).__init__(*args, **kwargs)
        
        # Your logic here
        if self.initial.get('original_field_widget'):
            self.fields['original_field'].widget = forms.HiddenInput()
            self.fields['original_field_widget'].widget.attrs['disabled'] = True
        else:
            self.fields['original_field_widget'].widget = forms.HiddenInput()

接下来,您需要传递重复元素的初始值。

<a href="{% url 'my_url_name' pk=object.pk %}?original_field={{ object.original_field }}&original_field_widget={{ object.original_field }}"> My link</a>
© www.soinside.com 2019 - 2024. All rights reserved.