Form preview in Django

Viewed 628

I am building a registration form. Whenever a user fills the form and clicks the register button I want them to see the preview of their submissions. I am having problems with the arguments. Here goes my code:

models.py

from django.db import models
from phonenumber_field.modelfields import PhoneNumberField

# Create your models here.
class Register(models.Model):
    regChoice = (
        ('Self', 'Self'),
        ('Group', 'Group'),
        ('Corporate', 'Corporate'),
        ('Others', 'Others'),
    )
    name = models.CharField(max_length=50)
    email = models.EmailField(max_length=254,null=True)
    phoneNumber = PhoneNumberField(null=True)
    idCard = models.ImageField(null=True)
    regType = models.CharField(max_length=25, choices=regChoice,null=True)
    ticketNo = models.IntegerField(default=1)

    def __str__(self):
        return self.name

forms.py

from django import forms
from django.forms import ModelForm
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from .models import *

class RegisterForm(ModelForm):
    name = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Your full name...'}))
    email = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Your email...'}))
    phoneNumber = forms.CharField(widget=forms.TextInput(attrs={'placeholder':'Your phone number...'}))

    class Meta:
        model = Register
        fields = '__all__'

urls.py

from django.urls import path
from . import views
urlpatterns = [
    path('', views.index, name='home'),
    path('preview.html/<str:pk>', views.preview, name="preview")
]

views.py

from django.shortcuts import render, redirect
from .models import *
from .forms import *
# Create your views here.
def index(request):
    form = RegisterForm()
    if request.method == 'POST':
        form = RegisterForm(request.POST, request.FILES)
        if form.is_valid():
            form.save()
    context = {'form':form}
    return render(request, 'event/index.html', context)

def preview(request, pk):
    reg = Register.objects.get(id=pk)
    prev = RegisterForm(instance=reg)
    if request.method == 'POST':
        form = RegisterForm(request.POST, instance=reg)
        if form.is_valid():
            form.save()
            return redirect('/')
    context = {'reg':reg, 'prev':prev}
    return render(request, 'event/preview.html', context)

index.html

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Event Registration</title>
    <link rel="stylesheet" href="{% static 'css/style.css' %}">
    <script src="{% static 'js/script.js' %}"></script>
</head>
<body>
    <div class="mobile-screen">
        <div class="header">
        </div>
        
        <div class="logo"></div>
      
        <form id="login-form" method="POST" action="{% url 'preview' form.id %}" enctype="multipart/form-data">
            {% csrf_token %}
                {{form.name}}
                {{form.email}}
                {{form.phoneNumber}}
                <legend style="color: aliceblue;">Upload ID card: </legend>{{form.idCard}}
                <div style="text-align: center; color: aliceblue;">Registration Type: {{form.regType}}</div>
                {{form.ticketNo}}
                <input class="btn btn-sm btn-primary" type="submit" value="Register" name="Register">
        </form>
        
      </div>
</body>
</html>

preview.html

Hello {{prev.name}},
your email is {{prev.email}}
your phone number is {{prev.phoneNumber}}
your idCard photo is {{prev.idCard.url}}
your registration type is {{prev.regType}}
your number of tickets is {{prev.ticketNo}}

The error I am having is:

NoReverseMatch at /

Reverse for 'preview' with arguments '('',)' not found. 1 pattern(s) tried: ['preview\.html/(?P[^/]+)$']

2 Answers

When someone reaches your index page and enters the form we need to

  1. Submit the form as a POST request to index view
  2. Save the form thereby creating a model in the DB
  3. Redirect the user to preview view using the above id

To do that the code needs to be somewhat like this, I have not tested it, but you should get the idea.

from django.shortcuts import redirect

def index(request):
    form = RegisterForm()
    if request.method == 'POST':
        form = RegisterForm(request.POST, request.FILES)
        if form.is_valid():
            instance = form.save()
            return redirect('preview', pk=instance.id)
    context = {'form':form}
    return render(request, 'event/index.html', context)

Inside your index.html change

action="{% url 'preview' form.id %}"

to

action=""

as we want it to post to the INDEX view as that is where out POST handling logic is.

The index view then redirects to preview using the newly generated object.

Also as mentioned by @Snir in the other answer, having .html in URLS is not a standard practice. It would be better to simple make it something like:

path('preview/<str:pk>', views.preview, name="preview")

The URL patterns are regexes, so you'll have to escape special regex characters, like the dot. Try (add r) or remove the dot:

    path(r'preview.html/<str:pk>', views.preview, 
    name="preview")
Related