Djangoはフォームが初期化された後にフィールド値を設定します


116

フォームが初期化された後、フィールドを特定の値に設定しようとしています。

たとえば、次のクラスがあります。

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

ビューでは、次のようなことができるようにしたいと思います。

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

return HttpResponse(t.render(c))

回答:


135

POSTデータを渡していないので、フォームに表示される初期値が設定されていると想定します。これを行う方法は、initialキーワードを使用することです。

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

詳細については、Djangoフォームのドキュメントをご覧ください。

フォームの送信後に値を変更する場合は、次のようなものを使用できます。

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

使用の詳細については、上記の参照ドキュメントを確認してください cleaned_data


2
これは私が知っていることを確認しModelChoiceFieldますが、initial値を指定すると、それでもinvalid_choiceを提供しています:(
markwalker_

はい、これも私の問題です。また、form.data ['Email']を変更することはできません。
GergelyPolonkai 2015年

2
私は私のものに変更しform.data['Email'] = GetEmailString()、それは機能します
psychok7 '29 / 10/29

1
CustomForm(request.POST)と.is_valid()のに設定する必要があるため、コンストラクターの初期値も、cleaned_dataも使用できません。form.dataを使用してみましたが、不変です(Django 1.11)。
Teekin

この質問に対する正しい解決策は次のとおりです。form.fields['Email'].initial = GetEmailString() これform.fields['keyword'].initialにより、フォームをインスタンス化した後でも値を初期化するためのアクセスが提供されます
vctrd

95

フォームを既に初期化している場合は、フィールドの初期プロパティを使用できます。例えば、

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

また、フォームセットのforループでもうまく機能します。「フォームセットのフォーム」のロジックを使用するだけで、上記のように選択肢と初期データを設定できます。
radtek、2014

5
これを行う別の方法はDjango 1.7 / Python 3.4ですか?これは私にとって
ジェレミー

1
@JeremyCraigMartinez:いいえ...フォームはバインドされたフォーム(GET / POSTデータが渡される)を試みていますか?ドキュメントによると、これが初期値が非バインドフォームに対してのみ表示される理由です。バインドされたフォームの場合、HTML出力はバインドされたデータを使用します。こちらを
Markus

9
正しい方法はform.initial ["Email"] = GetEmailString()です
Elio Scordo

12

__init__何らかの理由でフォームのメソッド内で実行したい場合は、initialdict を操作できます。

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'

最後に解決策を見つけました。ありがとうございました。それは私のために働いた。
アルマスDusal

8

収集した一連のフォームデータのコピーにデータを追加すると、Nigel Cohenのようなものが機能します。

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

1
私は生データを上書きすることはあまり好きではありません。これを絶対に行うdata[form.add_prefix('Email')]必要がある場合は、おそらく接頭辞が設定されている場合を考慮する必要があります。
Josh

2
これを行う別の方法はDjango 1.7 / Python 3.4ですか?これは私にとってはうまく
ジェレミー

:3行目は元の形を維持する必要はありませんもし少し短くすることができるform.data = form.data.copy()
ZZY

@ジョシュ、ここに必要性の1つのシナリオがあります。例:フォームに「名前」、「メール」、「コンテンツ」のフィールドがあります。「名前」と「メール」は保持しますが、「コンテンツ」は消去します。ユーザーが別のPOSTを送信する場合に、名前/メールアドレスを再度入力する必要がないようにします。もちろん、初期値と同じ名前/メールで新しいフォームを初期化するのも1つの方法ですが、場合によっては古いフォームの消去の方が簡単だと思います
ZZY

完全に理解しているのかわかりません。ただし、使用すると、代わりにを使用するように聞こえますmodelform_factory。このようにして、不要なフィールドを持たないFormクラスを生成できます。フォームオブジェクトはレンダリングされないフィールドのデータを引き続き受け入れるので、レンダリングされないフィールドを持つFormクラスを持つことは非常に危険です。攻撃者はこれを利用して攻撃者に悪用する可能性があります。
Josh、

5

このようなフォームを初期化した場合

form = CustomForm()

その後、2019年1月現在の正しい方法は.initial、データの置き換えに使用することです。これintialにより、フォームに沿った辞書のデータが置き換えられます。次のようなインスタンスを使用して初期化した場合にも機能します form = CustomForm(instance=instance)

フォームのデータを置き換えるには、以下を行う必要があります

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

これを一般化すると、

form.initial['field_name'] = new_value

3

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

0

ミックスにさらに別の方法を投入する場合:これも機能し、もう少し現代的な表記法を使用します。a 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">'

0

ウィジェットでは「値」属性を使用します。例:

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

-12

これを行うもう1つの方法は、フォームを(データありまたはなしで)初期化済みであり、フォームを表示する前にさらにデータを追加する必要がある場合です。

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

8
これは私には失敗します。フォームのinitメソッドに上記のような行があり、「AttributeError:This QueryDict instance is immutable」が発生します
Jonathan Hartley

このコードは、フォームがフォームデータなしで初期化されている場合にのみ機能します。その結果、request.GETやrequest.POSTなどの不変オブジェクトはバインドされないため、エラーなしで変更できる空の辞書(form.data)が取得されます。
ちなみに

これは、「Content-Type」ヘッダーが「multipart / form-data」に設定されている場合に機能します。「application / x-www-form-urlencoded」のコンテンツタイプを使用すると失敗します。理由はわかりませんが、デバッグするのは*****でした。
teewuane 2016年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.