Mastering Django Formsets: A Comprehensive Guide with an Invoice Example

How to use formset in creating objects of models and its related objects
August 14, 2024 by
Mastering Django Formsets: A Comprehensive Guide with an Invoice Example
Hamed Mohammadi
| No comments yet

Introduction

Django formsets are a powerful tool for handling multiple instances of a form on a single page. They're particularly useful when dealing with one-to-many relationships between models, such as an Invoice and its related Lines. In this tutorial, we'll walk through creating an Invoice app with Django formsets, covering models, forms, views, and templates.

Setting Up the Project and App

Let's assume you have a Django project set up. Create a new app named 'invoice':

$ python manage.py startapp invoice

Defining Models

We'll create two models: Invoice and Line. The Invoice model will have a one-to-many relationship with Line.

from django.db import models

class Invoice(models.Model):
    invoice_number = models.CharField(max_length=50)
    invoice_date = models.DateField()

class Line(models.Model):
    invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE)
    description = models.CharField(max_length=255)
    quantity = models.PositiveIntegerField()

Creating Forms

We'll create two forms: InvoiceForm for the invoice details and LineFormSet for the invoice lines.

from django import forms
from .models import Invoice, Line

class InvoiceForm(forms.ModelForm):
    class Meta:
        model = Invoice
        fields = ['invoice_number', 'invoice_date']

LineFormSet = forms.inlineformset_factory(Invoice, Line, fields=('description', 'quantity', 'unit_price'), extra=1, can_delete=True)


Writing Views

We'll create a view to handle the formset and save the data.

from django.shortcuts import render
from django.http import HttpResponseRedirect
from .forms import InvoiceForm, LineFormSet
from .models import Invoice

def invoice_create(request):
    if request.method == 'POST':
        invoice_form = InvoiceForm(request.POST)
        line_formset = LineFormSet(request.POST)

        if invoice_form.is_valid() and line_formset.is_valid():
            invoice = invoice_form.save()
            for line_form in line_formset:
                if line_form.cleaned_data:
                    line = line_form.save(commit=False)
                    line.invoice = invoice
                    line.save()
            return HttpResponseRedirect('/invoice/success/')  # Replace with appropriate URL
    else:
        invoice_form = InvoiceForm()
        line_formset = LineFormSet()

    return render(request, 'invoice/invoice_form.html', {'invoice_form': invoice_form, 'line_formset': line_formset})


Creating Templates

Create an HTML template to render the formset:

{% extendsbase.html%}

{% block content %}
    <form method="post">
        {% csrf_token %}
        {{ invoice_form.as_p }}
        {{ line_formset.management_form }}
        {% for form in line_formset %}
            {{ form.as_p }}
        {% endfor %}
        <button type="submit">Create Invoice</button>
    </form>
{% endblock %}


Explanation

  • We've created two models, Invoice and Line, with a one-to-many relationship.

  • The InvoiceForm handles the invoice details.

  • The LineFormSet handles multiple instances of the Line model.

  • The view handles form submission, saving the invoice and its lines.

  • The template renders the invoice form and the line formset.

Additional Considerations

  • Form validation: Implement custom validation for fields as needed.

  • Error handling: Display error messages appropriately.

  • Form styling: Use CSS to improve the form's appearance.

  • Form optimization: Consider using JavaScript to enhance user experience.

  • Security: Protect against vulnerabilities like CSRF and XSS.

This is a simple example that you can  have a solid foundation for using Django formsets to create dynamic and user-friendly forms for your applications.

Mastering Django Formsets: A Comprehensive Guide with an Invoice Example
Hamed Mohammadi August 14, 2024
Share this post
Archive

Please visit our blog at:

https://zehabsd.com/blog

A platform for Flash Stories:

https://readflashy.com

A platform for Persian Literature Lovers:

https://sarayesokhan.com

Sign in to leave a comment