表单初始化后Django设置字段值

Posted

技术标签:

【中文标题】表单初始化后Django设置字段值【英文标题】:Django set field value after a form is initialized 【发布时间】: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))

【问题讨论】:

【参考方案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”的内容类型时,它会失败。我不知道为什么,但它是一个 ***** 调试。

以上是关于表单初始化后Django设置字段值的主要内容,如果未能解决你的问题,请参考以下文章

使用自定义模板时 Django 表单字段的初始值

Django 表单集中每个表单的不同初始数据

Django Admin中的动态只读字段

Django - Admin 中的 ForeignKey 字段初始值定义

Django - UpdateView ModelForm 在查询集字段上设置初始值

Django在视图中从db查询初始表单值。