【问题标题】:Django set field value after a form is initialized表单初始化后Django设置字段值
【发布时间】:2010-10-23 05:47:20
【问题描述】:

我试图在表单初始化后将该字段设置为某个值。

例如,我有以下课程。

class CustomForm(forms.Form):
    Email = forms.EmailField(min_length=1, max_length=200)

在视图中,我希望能够做这样的事情:

form = CustomForm()
form["Email"] = GetEmailString()

return HttpResponse(t.render(c))

【问题讨论】:

    标签: django


    【解决方案1】:

    由于您没有传递 POST 数据,我假设您尝试做的是设置将在表单中显示的初始值。这样做的方法是使用 initial 关键字。

    form = CustomForm(initial={'Email': GetEmailString()})
    

    更多解释请参见Django Form docs

    如果您在提交表单后尝试更改值,您可以使用类似:

    if form.is_valid():
        form.cleaned_data['Email'] = GetEmailString()
    

    查看上面引用的文档以了解更多关于使用cleaned_data

    【讨论】:

    • 这证实了我所知道的,但是当我给它一个 initial 值时,我的 ModelChoiceField 仍然给出 invalid_choice :(
    • 我把我的改成了form.data['Email'] = GetEmailString(),它可以工作
    • 我需要设置它 CustomForm(request.POST) 和.is_valid() 之间,所以我不能在构造函数中使用initial,也不能使用cleaned_data。我尝试使用 form.data,但它是不可变的(Django 1.11)。
    • 这个问题的正确解决方案应该是:form.fields['Email'].initial = GetEmailString() form.fields['keyword'].initial 使您即使在实例化表单后也可以访问初始化值
    • 提交后尝试更改值时答案是错误的:有界表单无法更改,您必须创建一个新表单(使用新值)。见docs.djangoproject.com/en/3.0/ref/forms/api/…
    【解决方案2】:

    如果您已经初始化了表单,您可以使用该字段的初始属性。例如,

    form = CustomForm()
    form.fields["Email"].initial = GetEmailString()
    

    【讨论】:

    • 在带有表单集的 for 循环中也很有效,只需使用“表单集中的表单”逻辑,您就可以设置选项和初始数据,如上所示。
    • Django 1.7/Python 3.4 有什么不同的方法吗?这对我不起作用
    • @JeremyCraigMartinez:不...您尝试的表单是绑定表单(传入 GET/POST 数据)吗?文档说 这就是为什么只为未绑定的表单显示初始值的原因。对于绑定的表单,HTML 输出将使用绑定的数据。,请参阅here
    • 正确的方式是form.initial["Email"] = GetEmailString()
    【解决方案3】:

    如果您出于某种原因想在表单的__init__ 方法中执行此操作,则可以操作initial dict:

    class MyForm(forms.Form):
        my_field = forms.CharField(max_length=255)
    
        def __init__(self, *args, **kwargs):
            super(MyForm, self).__init__(*args, **kwargs)
            self.initial['my_field'] = 'Initial value'
    

    【讨论】:

    • 终于找到了解决办法。谢谢你。它对我有用。
    【解决方案4】:

    如果您将数据添加到收集的表单数据集的副本中,像 Nigel Cohen 这样的方法会起作用:

    form = FormType(request.POST)
    if request.method == "POST":
        formcopy = form(request.POST.copy())
        formcopy.data['Email'] = GetEmailString()
    

    【讨论】:

    • 我不喜欢覆盖原始数据。如果您绝对必须这样做,您可能应该使用data[form.add_prefix('Email')] 来解决设置前缀的情况。
    • Django 1.7/Python 3.4 有什么不同的方法吗?这对我不起作用
    • 第 3 行如果不需要保留原始形式,可以短一点:form.data = form.data.copy()
    • @Josh,这是需要的一种情况:使用表单验证输入 -> 处理输入 -> 处理完成 -> 擦除/修改表单的几个字段并呈现为 HTML回复。例如,表单中有“姓名”、“电子邮件”、“内容”字段,我想保留“姓名”和“电子邮件”,但删除“内容”。这样用户就不需要再次输入姓名/电子邮件,如果他们想提交另一个 POST。当然,使用与初始值相同的名称/电子邮件初始化一个新表单是一种方法,但我认为在某些情况下擦除旧表单更简单
    • 我不确定我是否完全理解。但是,如果我这样做了,我觉得您应该使用modelform_factory。这样,您可以生成一个没有您不想要的字段的 Form 类。拥有一个具有未呈现字段的 Form 类是非常危险的,因为表单对象仍将接受未呈现字段的数据。攻击者可以利用这一点。
    【解决方案5】:

    如果你已经像这样初始化了表单

    form = CustomForm()
    

    那么截至 2019 年 1 月,正确的方法是使用 .initial 替换数据。这将替换表单随附的intial dict 中的数据。如果您使用 form = CustomForm(instance=instance) 等实例进行了初始化,它也可以工作

    要替换表单中的数据,您需要

    form.initial['Email'] = GetEmailString()
    

    概括一下就是这样,

    form.initial['field_name'] = new_value
    

    【讨论】:

      【解决方案6】:

      只需更改您的 Form.data 字段:

      class ChooseProjectForm(forms.Form):
          project = forms.ModelChoiceField(queryset=project_qs)
          my_projects = forms.BooleanField()
      
          def __init__(self, *args, **kwargs):
              super(ChooseProjectForm, self).__init__(*args, **kwargs)
              self.data = self.data.copy()  # IMPORTANT, self.data is immutable
              # any condition:
              if self.data.get('my_projects'):
                  my_projects = self.fields['project'].queryset.filter(my=True)
                  self.fields['project'].queryset = my_projects
                  self.fields['project'].initial = my_projects.first().pk
                  self.fields['project'].empty_label = None  # disable "-----"
                  self.data.update(project=my_projects.first().pk)  # Update Form data
                  self.fields['project'].widget = forms.HiddenInput()  # Hide if you want
      

      【讨论】:

        【解决方案7】:

        再加入另一种方式:这也有效,带有更现代的符号。它只是解决了QueryDict 是不可变的事实。

        >>> the_form.data = {**f.data.dict(), 'some_field': 47}
        >>> the_form['some_field'].as_widget()
        '<input type="hidden" name="some_field" value="47"
                class="field-some_field" id="id_some_field">'
        

        【讨论】:

          【解决方案8】:

          在小部件中使用“值”属性。 示例:

          username = forms.CharField(
              required=False,
              widget=forms.TextInput(attrs={'readonly': True, 'value': 'CONSTANT_VALUE'}),
          )
          

          【讨论】:

            【解决方案9】:

            另一种方法是,如果您已经初始化了一个表单(有或没有数据),并且您需要在显示之前添加更多数据:

            form = Form(request.POST.form)
            form.data['Email'] = GetEmailString()
            

            【讨论】:

            • 这对我来说失败了。我在表单的 init 方法中有一条类似上面的行,它引发“AttributeError: This QueryDict instance is immutable”
            • 此代码仅在没有任何表单数据的情况下初始化表单时有效。因此,不会绑定像 request.GET 或 request.POST 这样的不可变对象,因此您将获得一个空字典(form.data),可以在没有任何错误的情况下进行更改。仅供参考,我正在使用 Django 1.6.3
            • 如果您的“Content-Type”标头设置为“multipart/form-data”,这将起作用。当您使用“application/x-www-form-urlencoded”的内容类型时,它会失败。我不知道为什么,但它是一个 ***** 调试。
            猜你喜欢
            • 1970-01-01
            • 2014-04-18
            • 2014-09-28
            • 2019-03-20
            • 2018-12-17
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多