私は少し前に同様のことをする必要がありました、そして以下は私たちが最終的に何をするかを説明しています。
ItemとUnfinishedItemの2つのテーブルがあります。ユーザーがウィザードでデータを入力すると、データはUnfinishedItemテーブルに保存されます。ウィザードの各ステップで、サーバーはそのステップ中に入力されたデータを検証します。ユーザーがウィザードを終了すると、ウィザードは非表示の読み取り専用フォームを、送信されるすべてのデータを示す確認ページにレンダリングします。ユーザーはこのページを確認し、関連する手順に戻ってエラーを修正できます。ユーザーが入力に満足したら、ユーザーは送信をクリックし、ウィザードは非表示/読み取り専用フォームフィールドのすべてのデータをAPIサーバーに送信します。APIサーバーはこのリクエストを処理するときに、ウィザードの各ステップで行ったすべての検証を再実行し、個々のステップに適合しない追加の検証を実行します(たとえば、グローバル検証、高価な検証)。
2つのテーブルアプローチの利点:
データベースでは、UnfinishedItemテーブルよりもItemテーブルに厳しい制約を課すことができます。ウィザードの終了時に実際に必要になるオプションの列を用意する必要はありません。
UnfinishedItemsを除外することを覚えておく必要がないので、レポート用に完成したItem全体のクエリを集約する方が簡単です。今回の場合、ItemとUnfinishedItemsの間で集計クエリを実行する必要がなかったため、これは問題になりません。
欠点:
- 検証ロジックが重複する傾向があります。私たちが使用したWebフレームワークであるDjangoは、ちょっとしたメタマジックを伴うモデル継承を使用して、ItemとUnfinishedItemで異なる必要がある制約を変更するので、これをもう少し耐えやすくします。Djangoはモデルからデータベースとフォームの検証のほとんどを生成します。その上に追加の検証をいくつか追加するだけで済みます。
私が検討したその他の可能性と、なぜ私たちがそれらを採用しなかったのか:
- Cookieまたはローカルストレージにデータを保存する:ユーザーは別のデバイスからの送信を続行できないか、ブラウザの履歴を削除した場合
- UnfinishedItemを非構造化データ(JSONなど)としてデータベースまたはセカンダリデータストアに保存します。解析ロジックを定義する必要があり、Djangoの自動モデル/フォーム検証を使用できません。
- クライアント側でステップごとの検証を行います。Python/ DjangoとJavaScriptの間で検証ロジックを複製する必要があります。