Using Django FormPreview in the right direction

My goal

I have a django project with a form and I want to display a preview page before the user submits.

Problem

I can display the preview page using Django FormPreview , but not all form data is displayed correctly. In particular, if I have a field with choices

, the string values ​​of those options are not displayed. I am also having problems with pattern filters on date fields. The end result is that some data is visible on the preview page, but other data is empty:

Preview page

However, if I show the same data for messages that were actually sent, then everything is displayed correctly:

Submitted page

My code

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'
    )

      

I'm sure the problem is in my view.py: I'm not sure if I'm handling the request POST

correctly to pass all the data to the preview page.

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

...
<form method="post">
  {% csrf_token %}
  <ul><li>{{ form.as_p }}</li></ul>

  <button type="submit">Preview your post</button>
</form>
...

      

preview.html

{% load humanize %}
...
<h1>Preview your submission</h1>

  <div>
    <p>Location: {{ form.data.location }}</p>
    <p>Game Date: {{ form.data.game_date|date:"l, F d, Y" }}</p>
    <p>Game Type: {{ form.data.get_game_display }}</p>
  </div>

  <div>
    <form action="{% url 'form_upload' %}" method="post">
      {% csrf_token %}
      {% for field in form %}
      {{ field.as_hidden }}
      {% endfor %}
      <input type="hidden" name="{{ stage_field }}" value="2" />
      <input type="hidden" name="{{ hash_field }}" value="{{ hash_value }}" />

      <!-- Submit button -->
      <button type="submit">Submit your post</button>
      <!-- Go back button -->
      <button type="submit">
        <a href="{% url 'form_upload' %}" 
          onClick="history.go(-1);return false;" >
          Go back and edit your post
        </a>
      </button>

      </div>

    </form>
  </div>
...

      

Two problems

Essentially, I am having the following two problems:

  • String values ​​for are choices

    not displayed. If I use get_FOO_display () method in my template preview.html

    it will be empty. However, if I use this on the page after posting the post, it displays correctly.
  • Date filter humanize

    doesn't work. If I apply filter humanize

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

    ) in preview.html

    , it also displays empty. Again, this works for the submitted posts.

My question is basically this: what's the correct way to use FormPreview

here?

+3


source to share


1 answer


form.data

has no attributes get_FOO_display

. When you access {{ form.data.get_game_display }}

in the template it fails and displays nothing.

get_FOO_display

are instance methods, so try that instead.

{{ form.instance.get_game_display }}

      

Whenever possible, you should access the data from form.cleaned_data

(which is validated and "cleared") instead of form.data

that raw data submitted to the form.



Filters don't work with form.data.game_date

because it's a raw string. They should work with form.cleaned_data.game_date

which has been converted to python date object.

Finally, you haven't implemented anything in your method done

, you just copied the comment from the docs. You can create a new game using the cleaned_data

following:

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

      

+1


source







All Articles