【问题标题】:Modify value of a Django form field during clean()在 clean() 期间修改 Django 表单字段的值
【发布时间】:2026-01-09 17:50:02
【问题描述】:

我正在向我的 Django 应用程序中的表单和自定义字段添加自定义验证。我希望能够在触发错误时修改字段的值。例如,如果出现错误,应重新显示表单,并使用 clean() 更正的字段值和错误消息“数据已在下面更正。再次单击保存以确认这些更改是否正常”

我尝试过像这样在 clean_data[] 中返回修改后的数据,但它不起作用。它正确显示错误,但在重新显示表单时,字段值不会使用更正的 HTML 更新。

class T34AtividadeForm(ModelForm):
    def clean(self):
        # Return cleaned html
        error,html = fix_imgs(cleaned_data.get("a34_descricao"))
        if error:
            msg = u'Data has been corrected below. Click save again to confirm if these changes are OK';
            self._errors['a34_descricao'] = ErrorList([msg])
            # This doesn't work
            cleaned_data["a34_descricao"] = html
            # This doesn't work either
            self.a34_descricao = html

    return cleaned_data

我也想对字段做同样的事情,但由于错误是由异常触发的,我没有机会返回更正后的值。和form clean()方法一样,错误显示正确,但是值没有更新。

class HTMLField(CharField):
    widget = HTMLTextarea

    def clean(self, value):
        value = super(HTMLField,self).clean(value)
        error,html = fix_imgs(value)
        if error:
            # This doesn't work
            self.value = html
            raise forms.ValidationError(u'Data has been corrected below. Click save again to confirm if these changes are OK.')
        return html

【问题讨论】:

    标签: django django-forms


    【解决方案1】:

    我在另一个清理函数中为特定字段设置了一个值,但它没有工作,因为它被主清理函数覆盖了。为了设置值并保留它:

    • 没有工作。
        def clean_tipo_cupon(self):
            tipo_cupon = self.cleaned_data['tipo_cupon']
            qscu = mdlcat.TipoCuponVenta.objects.filter(
                id=tipo_cupon, estado_id=1,
            )
            if not qscu.exists():
                wmessage = u'introducido no paso validación'
                raise forms.ValidationError(wmessage)
    
            qscu = qscu.first()
            if not qscu.default_owner is None:
                self.cleaned_data['default_owner'] = qscu.default_owner.id
    
            return tipo_cupon
    
    
    • 在这里,它就像一个魅力。
        def clean(self):
            cleaned_data = super().clean()
            for item in self.fields.keys():
                if isinstance(cleaned_data.get(item), str):
                    cleaned_data[item] = cleaned_data.get(item).upper()
    
            # if a default owner is configured by coupon type
            # it will be assigned
            tipo_cupon = cleaned_data['tipo_cupon']
            qscu = mdlcat.TipoCuponVenta.objects.filter(
                id=tipo_cupon, estado_id=1,
            )
            qscu = qscu.first()
            if not qscu.default_owner is None:
                self.cleaned_data['default_owner'] = qscu.default_owner.id
    
            return cleaned_data
    

    【讨论】:

      【解决方案2】:

      我们不能重定向编辑request.data,因为它是一个不可变的字典。你需要复制它,做你的东西并返回它。

      但是在不同的解决方案之后,我发现了这种方式(在 Django 2.2.6 中测试)

      class MyForm(ModelForm):
      
          def clean(self):
              cleaned_data = super(MyForm, self).clean()
              self.instance.field = 'value'
              return cleaned_data
      
      

      【讨论】:

        【解决方案3】:

        如果更新表单的self.data 属性,则可以在clean() 期间修改字段的值。 self.dataQueryDict 类的一个实例。默认情况下,querydicts 是不可变的。要使它们可变,您应该使用.copy() 方法。来自文档:

        在正常的请求/响应周期中访问时,request.POST 和 request.GET 中的 QueryDicts 将是不可变的。要获得可变版本,您需要使用 QueryDict.copy()

        self.data = self.data.copy()
        self.data['your_field'] = 'new value'
        

        【讨论】:

          【解决方案4】:

          在 clean() 中更新值的方法是更新表单数据字典中的值:

          self.data["a34_stuff"] = "html"
          

          这确实有效。

          【讨论】:

          • 1.11 也没有!
          【解决方案5】:

          这是我尝试过并为我工作的方式:

           inst = my_form.save(commit=False)
           if not inst.a34_stuff: # or incorrect
               inst.data["a34_stuff"] = "corrected"
          

          【讨论】:

            【解决方案6】:

            如果您的表单是模型表单,更好的方法是获取实例并改正该数据:

            inst = my_form.save(commit=False)
            if inst.a34_stuff is None: #or incorrect
                inst.a34_stuff = "corrected"
                request.user.message_set.create(message = "Error corrected")
                return HttpResponseRedirect(reverse('your_url_name',
                        args=[])
            

            PS:我不确定这是否真的有效...不确定表单是否会改变。

            【讨论】:

              【解决方案7】:

              在 clean 方法中更改 self 数据以更改显示的值

              【讨论】:

              • 这行得通,但没有记录,直接修改 QueryDict 对象感觉很难看。此外,我必须编写一个辅助函数来修改只读 QueryDict....
              • @user27478:你能发布你的解决方案吗?
              • 在 Django 2.0 中,cleaned_data = super().clean()(或同等版本)中,修改 cleaned_data 字典并确保在函数末尾添加 return cleaned_data
              • 请注意,这仅在可编辑的表单字段被更改时才有效,否则不会保存任何更改。
              最近更新 更多