Eu precisava fazer algo semelhante há algum tempo, e o seguinte descreve o que terminamos.
Temos duas tabelas, Item e UnfinishedItem. Quando o usuário preenche os dados com o assistente, os dados são armazenados na tabela UnfinishedItem. Em cada etapa do assistente, o servidor valida os dados inseridos durante essa etapa. Quando o usuário termina o assistente, ele cria um formulário oculto / somente leitura em uma página de confirmação que mostra todos os dados a serem enviados. O usuário pode revisar esta página e voltar à etapa relevante para corrigir erros. Quando o usuário estiver satisfeito com suas entradas, o usuário clica em enviar e o assistente envia todos os dados nos campos de formulário oculto / somente leitura para o servidor da API. Quando o servidor da API processa essa solicitação, ele executa novamente todas as validações realizadas durante cada etapa do assistente e executa validações adicionais que não se encaixam nas etapas individuais (por exemplo, validações globais, validações caras).
As vantagens da abordagem de duas tabelas:
no banco de dados, você pode ter restrições mais rígidas na tabela Item do que na tabela UnfinishedItem; você não precisa ter colunas opcionais que serão realmente necessárias quando o assistente for concluído.
As consultas agregadas nos itens concluídos para geração de relatórios são mais fáceis, pois você não precisa se lembrar de excluir os UnfinishedItems. No nosso caso, nunca precisamos fazer consultas agregadas entre Item e UnfinishedItems, portanto, isso não é um problema.
A desvantagem:
- É propenso a duplicação da lógica de validação. A estrutura da web que usamos, Django, torna isso um pouco mais suportável, pois usamos a herança de modelo com um pouco de meta mágica para alterar as restrições que precisamos ser diferentes em Item e UnfinishedItem. O Django gera a maior parte do banco de dados e a validação de formulário a partir do modelo, e precisamos apenas de algumas validações adicionais sobre ele.
Outras possibilidades que considerei e por que não as acompanhamos:
- salvar os dados em cookies ou armazenamento local: o usuário não pode continuar enviando a partir de um dispositivo diferente ou se excluir o histórico do navegador
- armazene o UnfinishedItem como dados não estruturados (por exemplo, JSON) no banco de dados ou no armazenamento de dados secundário: vou ter que definir a lógica de análise e não posso usar a validação automática de modelo / formulário do Django.
- faça a validação por etapa no lado do cliente: terei que duplicar a lógica de validação entre Python / Django e JavaScript.