Usando o Django FormPreview do jeito certo

Meu gol

Eu tenho um projeto de django com um formulário e quero exibir uma página de visualização antes do envio do usuário.

O problema

Eu posso exibir uma página de visualização usando um Django FormPreview , mas nem todos os dados do formulário são exibidos corretamente. Especificamente, se eu tiver um campo com choices , os valores de sequência dessas opções não serão exibidos. Também estou tendo problemas ao aplicar filtros de modelo a campos de data. O resultado final é que alguns dados na página de visualização estão visíveis, mas outros dados estão em branco:

Página de pré-visualização

No entanto, se eu exibir os mesmos dados para as postagens que realmente foram enviadas, tudo será exibido corretamente:

Página enviada

Meu código

models.py :

 class Game(models.Model): # Game Choices FOOTBALL = 0 BASKETBALL = 1 TENNIS = 2 OTHER = 3 GAME_CHOICES = ( (FOOTBALL, 'Football'), (BASKETBALL, 'Basketball'), (TENNIS, 'Tennis'), (OTHER, 'Other') ) game_id = models.AutoField(primary_key=True) location = models.CharField(max_length=200, verbose_name="Location") game = models.IntegerField(choices=GAME_CHOICES, default=FOOTBALL) game_date = models.DateField(verbose_name='Game Date') 

forms.py

 class GameForm(ModelForm): class Meta: model = Game fields = ( 'location', 'game', 'game_date' ) 

Tenho certeza de que o problema está no meu views.py: Não tenho certeza se estou processando a solicitação POST da maneira correta para alimentar todos os dados para a página de visualização.

views.py

 def form_upload(request): if request.method == 'GET': form = GameForm() else: # A POST request: Handle Form Upload form = GameForm(request.POST) # Bind data from request.POST into a GameForm # If data is valid, proceeds to create a new game and redirect the user if form.is_valid(): game = form.save() return render(request, 'games/success.html', {}) return render(request, 'games/form_upload.html', { 'form': form, }) 

preview.py

 class GameFormPreview(FormPreview): form_template = 'games/form_upload.html' preview_template = 'games/preview.html' def done(self, request, cleaned_data): # Do something with the cleaned_data, then redirect # to a "success" page. return HttpResponseRedirect('/games/success') 

form_upload.html

 ...  {% csrf_token %} 
  • {{ form.as_p }}
...

preview.html

 {% load humanize %} ... 

Preview your submission

Location: {{ form.data.location }}

Game Date: {{ form.data.game_date|date:"l, F d, Y" }}

Game Type: {{ form.data.get_game_display }}

{% csrf_token %} {% for field in form %} {{ field.as_hidden }} {% endfor %}
...

Dois problemas

Essencialmente, estou tendo estes dois problemas:

  1. Valores de seqüência de caracteres para choices não são exibidos. Se eu usar o método get_FOO_display () no meu modelo preview.html , ele retornará em branco. No entanto, se eu usar isso em uma página após o envio da postagem, ela será exibida corretamente.
  2. O filtro humanize data não funciona. Se eu aplicar um filtro de humanize ( {{ form.data.game_date|date:"l, F d, Y" }} ) em preview.html , ele também será exibido em branco. Mais uma vez, isso funciona para postagens enviadas.

A minha pergunta é essencialmente: qual é o caminho certo para usar o FormPreview aqui?

form.data não possui atributos get_FOO_display . Quando você acessa o {{ form.data.get_game_display }} no modelo, ele falha silenciosamente e não exibe nada.

Os get_FOO_display são methods da instância, então tente isso.

 {{ form.instance.get_game_display }} 

Sempre que possível, você deve acessar dados de form.cleaned_data (que é validado e ‘limpo’) em vez de form.data , que são os dados brutos enviados ao formulário.

Os filtros não funcionam com form.data.game_date porque é uma string não processada. Eles devem trabalhar com form.cleaned_data.game_date , que foi convertido em um object de data python.

Finalmente, você não implementou nada no seu método done , apenas copiou o comentário dos documentos. Você poderia criar um novo jogo usando o cleaned_data seguinte maneira:

 def done(self, request, cleaned_data): game = Game.objects.create(**cleaned_data) return HttpResponseRedirect('/games/success')