Django 未通过禁用字段-需要解决方法

Django 未通过禁用字段-需要解决方法,django,django-forms,Django,Django Forms,我有一个表单,我想用它更新MyModel对象。在模型上有一个唯一的约束,即fieldA和fieldB。在clean方法的表单中,我检查这个唯一的约束 出于某些原因,我不得不在更新中将fieldA显示为只读。因此,fieldA不会通过。我的问题是,如果表单未验证,表单将重新显示,但我在fieldA中丢失了值 我试图重置已清理的_数据['fieldA'],但它不起作用。 你知道要改变什么吗 Forms.py class MyModelUpdateForm(forms.ModelForm):

我有一个表单,我想用它更新MyModel对象。在模型上有一个唯一的约束,即fieldA和fieldB。在clean方法的表单中,我检查这个唯一的约束

出于某些原因,我不得不在更新中将fieldA显示为只读。因此,fieldA不会通过。我的问题是,如果表单未验证,表单将重新显示,但我在fieldA中丢失了值

我试图重置已清理的_数据['fieldA'],但它不起作用。 你知道要改变什么吗

Forms.py

class MyModelUpdateForm(forms.ModelForm):
    class Meta:
        model = MyModel

    def __init__(self, *args, **kwargs):
        super(MyModelUpdateForm, self).__init__(*args, **kwargs)
        self.fields['fieldA'].widget.attrs['readonly'] = True
        self.fields['fieldA'].widget.attrs['disabled'] = True

    def clean(self):
        cleaned_data = self.cleaned_data
        fieldA= self.instance.fieldA
        fieldB = cleaned_data.get("fieldB")

        if MyModel.objects.filter(fieldA=fieldA, fieldB=fieldB).count() > 0:
            #try to reset fieldA, since it is not passed through, since it is disabled
            cleaned_data['fieldA'] = fieldA.pk #does not work
            raise forms.ValidationError('some unique validation error')
        return cleaned_data
Views.py:

myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id)

    if request.method == 'POST':
        model_form = MyModelUpdateForm(request.POST, instance=myModelobject )

        if model_form .is_valid():
           ....

我对表单的工作原理有点兴趣,并提出了多种解决方案,只是为了见鬼

由于您禁用的是小部件,而不是字段,因此就表单而言,它始终没有收到fieldA的任何信息,这将始终导致验证失败

尝试clean()方法对无效表单没有帮助,因为
clean()
数据用于处理

表单为HTML显示拉取数据的方式似乎是
field.data
,这是从\u datadict(POST,FILES,field\u name)调用
field.widget.value\u,因此它将始终查看您的POST数据

所以我认为你有几个选择。Hack
request.POST
,Hack内部表单POST数据,或Hack
value\u from\u datadict


黑客
request.POST
:直截了当,有道理

    myModelobject = get_object_or_404(MyModel.objects, pk=mymodel_id)

        if request.method == 'POST':
            POST = request.POST.copy()
            POST['fieldA'] = myModelobject.fieldA
            model_form = MyModelUpdateForm(POST, instance=myModelobject )

            if model_form .is_valid():
                # ...
黑客内部字典:

def __init__(self, *args, **kwargs):
    super(MyModelUpdateForm, self).__init__(*args, **kwargs)
    self.data.update({ 'fieldA': self.instance.fieldA })
从datadict中黑客
value\u:有点可笑,但说明了从挖掘源代码中可以学到什么

def __init__(self, *args, **kwargs):
    super(MyModelUpdateForm, self).__init__(*args, **kwargs)
    self.fields['fieldA'].widget.value_from_datadict = lambda *args: self.instance.first_name

在这里学到了一些很酷的东西:)希望能有所帮助。

我也遇到过类似的问题,我就是这样解决的

我将字段设置为隐藏:

self.fields['fieldA'].widget.attrs['style'] = 'display:none;'
在模板中,我分别显示字段值:

{{ form.fieldA.label_tag }}
{{ form.fieldA }}
{{ form.fieldA.value }}
{{ form.fieldA.errors }}
如果是fieldA,则为选择菜单:

{{ form.fieldA.label_tag }}
{{ form.fieldA }}
{% for value, title in form.fields.fieldA.choices %}
    {% if value == form.fieldA.value %}
        {{ title }}
    {% endif %}
{% endfor %}
{{ form.fieldA.errors }}

您可以将其放在form类中,如下所示:

class MyForm(forms.Form):

    MY_VALUE = 'SOMETHING'
    myfield = forms.CharField(
        initial=MY_VALUE,
        widget=forms.TextInput(attrs={'disabled': 'disabled'})

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

        # If the form has been submitted, populate the disabled field
        if 'data' in kwargs:
            data = kwargs['data'].copy()
            self.prefix = kwargs.get('prefix')
            data[self.add_prefix('myfield')] = MY_VALUE
            kwargs['data'] = data

        super(MyForm, self).__init__(*args, **kwargs) 

它的工作方式是测试是否有数据传递给表单构造函数。如果有,它会复制它(未复制的数据是不可变的),然后在继续实例化表单之前输入初始值。

我在不涉及后端部分的情况下解决了此问题,您只需使用“可见性:隐藏”属性将特定类添加到forms.py中的fieldA

self.fields['fieldA'].widget.attrs['class'] = 'visibility_hidden_class'
然后,在模板中,您的form.fieldA将被隐藏,但不会在post请求中丢失

{{ form.fieldA.label_tag }}
{{ form.fieldA }}
<input type="text" value="{{ form.fieldA.value }}" disabled />
{{form.fieldA.label_tag}
{{form.fieldA}}

因此,您仍将在请求表单数据中保留form.fieldA。从视觉上看,您的字段将始终填充.fieldA.value表单。

我必须解决一个类似的问题。我使用like-dinamyc formset生成新行,因此一旦选择产品,它就会显示为禁用,但我需要在视图中获取表单上的值。Jquery和JavaScript对我来说更容易,所以我生成了一个预发送事件,删除了我在表单集中使用的选择器上的禁用项。我在使用小部件select2进行此设置,因此它也适用于select2

当然,发送按钮id=“postForm”和表单id=“contractForm”的id是相同的


我使用jQuery解决了这个问题,在提交之前从所有输入中删除禁用项

$('#my_form').submit(function(){
    $("#my_form :disabled").removeAttr('disabled');
});

models.py中添加
blank=True

例如:

class myModel(models.Model):
      myField = models.CharField(max_length=30, blank=True)

我知道这是一个老问题,但我最近自己也遇到了这个问题。我认为最简单的解决方案是在init定义中使用“initial”:

def __init__(self, *args, **kwargs):
    super(MyModelUpdateForm, self).__init__(*args, **kwargs)
    self.fields['fieldA'].disabled = True
    self.fields['fieldA'].initial = self.instance.fieldA

当然,这假设实例已经存在。如果需要,您可能需要添加一个“if”子句。

Nice,但是如果出现复选框,您该怎么办呢。你们如何区分复选框被禁用还是未选中。我发现对输入元素使用“readonly”比破解帖子或@BehnamHeydari问题是关于使用“只读”阻止数据发送的事实。谢谢你的回答。在破解内部dict时,我得到了一个
这个QueryDict实例是不可变的
异常。因此,我最终修补了来自_datadict
函数的
值。
def __init__(self, *args, **kwargs):
    super(MyModelUpdateForm, self).__init__(*args, **kwargs)
    self.fields['fieldA'].disabled = True
    self.fields['fieldA'].initial = self.instance.fieldA