4

新しいモデルを作成するか、既存のモデルを編集するモデルフォームがあります。これは簡単で動作するはずですが、何らかの理由で毎回新しいインスタンスを取得しています。

シナリオは、これが e コマース注文の最初のステップです。ユーザーは、注文を説明する情報を入力する必要があります (モデルに保存されます)。モデルを作成して保存し、ユーザーが CC 情報を入力できるように次のビューにリダイレクトします。次のビューで DB ルックアップを行う必要がないように、モデルをセッションに貼り付けます。テンプレートには、ユーザーが最初のビューに戻って注文を編集できるようにする 2 番目の (cc 情報) ビューのリンクがあります。

# forms.py

class MyForm(forms.ModelForm):
    class Meta:
        fields = ('field1', 'field2')
        model = MyModel

# views.py

def create_or_update(request):
    if request.method == 'POST':
        form = MyForm(request.POST)
        if form.is_valid():
            m = form.save(commit=False)
            # update some other fields that aren't in the form
            m.field3 = 'blah'
            m.field4 = 'blah'
            m.save()
            request.session['m'] = m
            return HttpResponseRedirect(reverse('enter_cc_info'))
        # invalid form, render template
        ...
    else:
        # check to see if we're coming back to edit an existing model
        # this part works, I get an instance as expected
        m = request.session.get('m', None)
        if m:
            instance = get_object_or_None(MyModel, id=m.id)
            if instance:
                form = MyForm(instance=instance)
            else:
                # can't find it in the DB, but it's in the session
                form = MyForm({'field1': m.field1, 'field2': m.field2})
        else:
            form = MyForm()

    # render the form
    ...

ビューに戻って、以前に作成されたモデルに設定されたインスタンスでフォームが作成される順序を編集するときに、デバッガーをステップスルーすると、期待どおりです。ただし、後続の POST でフォームが処理されると、form.save() が呼び出されたときにモデルの新しいインスタンスが作成されます。

これは、フォームのフィールドを制限したためだと思います。レンダリングされた HTML には、既存のモデルへの ID (またはその他の参照) を格納する場所がありません。ただし、「pk」フィールドと「id」フィールドの両方を (同時にではなく) 追加しようとしましたが、フォームがまったくレンダリングされません。

これを必要以上に複雑にしているのではないかと思いますが、現時点では行き詰まっており、フィードバックを使用できます。前もって感謝します。

4

1 に答える 1

10

これは面白い。これが私の突き刺しです。次の行を検討してください。

form = MyForm(request.POST)

の内容を確認できますrequest.POSTか? 具体的には、モデルのどのインスタンスが編集されているかに関する情報があるかどうかを確認します。何もないことがわかります。つまり、フォームを保存するたびにPOST、新しいインスタンスが作成されます。

なぜこれが起こるのですか?キーワード引数を渡してフォームを作成するinstance=instanceと、モデルのインスタンスのインスタンスを返すよう Form クラスに指示されます。ただし、フォームをテンプレートにレンダリングする場合、この情報はフィールドへの入力のみに使用されます。つまり、特定のインスタンスに関する情報が失われます。当然、パックを投稿すると、古いインスタンスに接続する方法があります。

どうすればこれを防ぐことができますか? 一般的なイディオムは、主キーを URL の一部として使用し、 でインスタンスをルックアップすることPOSTです。次に、フォームを作成します。あなたの場合、これは次のことを意味します:

def create_or_update(request, instance_id):
#                             ^^^^^ 
#                             URL param
    if request.method == 'POST':
        instance = get_object_or_None(Model, pk = instance_id)
        # ^^^^^
        # Look up the instance

        form = MyForm(request.POST, instance = instance)
        #                           ^^^^^^^
        #                           pass the instance now.
        if form.is_valid():
              ....
于 2010-10-06T16:52:26.367 に答える