user9252255
user9252255

Reputation:

Django: Combining forms & models to generate form

I have an issue with my Django forms and combining it with data from my database.

  1. I need to get data about tickets to generate the form via {% for ticket in tickets %}
  2. Once the user chose the ticket(s) and quantity, the form will check this request. I wanted to use Form.is_valid() and cleaned_data, however, I couldn't manage to combine this with step 1.

Do you guys have any tips or input how I can make my code more "safe"? Currently, I am skipping all the provided security Django provides with cleaned_data and is_valid(). The reason why is that I don't know how to do it.

views.py

from django.shortcuts import render

from .models import Ticket
from tickets.models import Order, Entry

# Create your views here.
def choose_ticket_and_quantity(request):

    tickets = Ticket.objects.all()

    if request.POST:
        o = Order.objects.create()
        request.session['order_id'] = o.order_id

        ticket_id = request.POST.getlist('ticket_id')
        ticket_quantity = request.POST.getlist('ticket_quantity')
        for x in range(len(ticket_id)):
            if int(ticket_quantity[x]) > 0:
                e = Entry(
                        order=Order.objects.get(order_id = o.order_id),
                        ticket=Ticket.objects.get(id = ticket_id[x]),
                        quantity=ticket_quantity[x]
                    ).save()

    return render(request, "tickets/choose_ticket_and_quantity.html", {"tickets": tickets})

models.py

class Ticket(models.Model):
    description     = models.TextField()
    name            = models.CharField(max_length=120)
    price_gross     = models.DecimalField(max_digits=19, decimal_places=2)
    quantity        = models.IntegerField()

choose_ticket_and_quantity.html

<form action="" method="post">
  {% csrf_token %}

  {% for ticket in tickets %}
    <input type="hidden" name="ticket_id" value="{{ ticket.id }}">

    {{ ticket.name }}

    <select name="ticket_quantity" >
      <option value="0">0</option>
      <option value="1">1</option>
      <option value="2">2</option>
      <option value="3">3</option>
    </select>

  {% endfor %}

  <p><input type="submit" value="Checkout"></p>
</form>

Here what I currently tried/started within forms.py But I don't know how to render the *.html while getting the ticket data from its model.

from django import forms

#Currently not used
INT_CHOICES = [tuple([x,x]) for x in range(0,11)]

class TicketForm(forms.Form):
    ticket_quantity     = forms.IntegerField(widget=forms.Select(choices=INT_CHOICES))

Upvotes: 1

Views: 478

Answers (1)

Nayan
Nayan

Reputation: 1605

You can create a EntryModelForm for your Entry model and then create a FormSet of EntryModelForm.

Django Formset documentation

Here is sample view function:

from django.forms import formset_factory

def choose_ticket_and_quantity(request):

    tickets = []
    for ticket in Ticket.objects.all():
        tickets.append({'ticket': ticket})

    EntryFormSet = formset_factory(EntryModelForm, extra=0)
    formset = EntryFormSet(initial=tickets)

    if request.POST:
        o = Order.objects.create()

        formset = EntryFormSet(request.POST, initial=tickets)
        for form in formset:
            if form.is_valid():
                entry = form.save(commit=False)
                entry.order = o
                entry.save()

    return render(request, "tickets/choose_ticket_and_quantity.html",
                  {'formset': formset})

I guess your entry model class might be something like the following:

class Entry(models.Model):
    order = models.ForeignKey(Order, on_delete=models.CASCADE)
    ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
    quantity = models.IntegerField(choices=INT_CHOICES)

Here is the form class:

class EntryModelForm(forms.ModelForm):
    class Meta:
        model=Entry
        exclude = ('order',)

Here is the HTML template:

<form action="" method="post">
  {% csrf_token %}
  {{ formset }}
  <p><input type="submit" value="Checkout"></p>
</form>

Upvotes: 1

Related Questions