Tech Incent
DjangoDjango Form

Explained Django inline formset factory with example?

explained-django-inline-formset-factory-with-example

Recently I have completed an eCommerce project. I used Django forms interesting feature formset factory. It’s simple forming but it’s useful. So why useful, why where you need formset factory function.
Simply we are used formset factory form multi-form in a single view. so why we use multi-form in single? You saw there are scenario models related fields or foreign key fields. Now we want to create/update models foreign key fields on one page/the same page.

So I am going to explain django inline formset factory with example…

Explain inlineformset_factory

Inlineformset_factory is the method. to work django related objects via a foreign key. django call it small abstraction layout on the top of models formset

inlineformset_factory(parent_model, model, form=ModelForm,
                          formset=BaseInlineFormSet, fk_name=None,
                          fields=None, exclude=None, extra=3, can_order=False,
                          can_delete=True, max_num=None, formfield_callback=None,
                          widgets=None, validate_max=False, localized_fields=None,
                          labels=None, help_texts=None, error_messages=None,
                          min_num=None, validate_min=False, field_classes=None)

So inline formset requirements parent_model as first param, model as the second param, and form param value as ModelForm. So have a look params description …

  • parent_model*: Provide the foreign key model. which was defined in model foreign key.
  • model*: Define the model class which was created a formset.
  • form*: Define the model form which model was used in model param
  • formset: Provide model formset whcih was override BaseInlineFormSet, by default BaseInlineFormSet is provided by django.
  • fk_name: If your model contains more than one foreign key then you must provide fk_name, by default it is none.
  • fields: Provide the model form fields to include as part of the model to create the model formset — just like the fields meta model form option
  • exclude: The defined model meta defines deleting model form fields as part of the model to create a model formset similar to the form option.
  • extra: Provide the number of the extra fields, you want to show, by default was 3.
  • can_order: Specify true if you want to control your formset. by default it is false.
  • can_delete:  By default formset items is deletable. providing False value, can’t delete formset item
  • max_num: Provide the number of max formset items you want to limit.
  • validate_max: Raise the number of max formset items validation. by default it’s False.
  • formfield_callback: Providing formfield_callback to customize the model form field. this method will execute prior to creating a form field from a model field.
  • widgets: Providing custom widgets to customization form fields, default it is none.
  • localized_fields: localized_fields makes models formset field as multiple languages support.. it like the model form meta option.
  • labels: Providing label overrides formset field labels. it like model form meta option
  • helper_texts: Providing helper_text overrides formset field helper tests. it like model form meta option
  • error_messages: Overriding error messages for formset form field. it like model form meta option
  • min_num: Provide the number of min formset items you want to limit.
  • validate_min: Raise the number of min formset items validation. by default it’s False.
  • field_classess: providing field_classess overriding field classes for the model form to create the model formset.

In Django 3.2 version two fields added

  • absolute_max:
  • can_delete_extra: control extra fields delectable, by default it’s False.

Example of  inlineformset_factory

For setup, create models

class Product(models.Model):
    """ Product """
    name = models.CharField(max_length=250)
    price = models.PositiveIntegerField()

    def __str__(self):
        return self.name

class ProductMeta(models.Model):
    """ Product Meta """
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    name = models.CharField('Property', max_length=50)
    value = models.CharField(max_length=200, blank=True, null=True)

    def __str__(self):
        return f'Id: {self.pk }, {self.name} for ProductId: {self.product.pk}'

Great we created models call Product and ProductMeta. So we are ready for formset example

Inline Formset factory

  1. Create inline form Factory

    In forms.py file create product model form and product meta model form

    from django import forms
    from django.forms import inlineformset_factory
    
    from .models import Product, ProductMeta
    
    
    class ProductForm(forms.ModelForm):
        class Meta:
            model = Product
            fields = ('name', 'price')
    
    
    class ProductMetaForm(forms.ModelForm):
        class Meta:
            model = ProductMeta
            fields = ('name', 'value')
    
    
    ProductMetaInlineFormset = inlineformset_factory(
        Product,
        ProductMeta,
        form=ProductMetaForm,
        extra=5,
        # max_num=5,
        # fk_name=None,
        # fields=None, exclude=None, can_order=False,
        # can_delete=True, max_num=None, formfield_callback=None,
        # widgets=None, validate_max=False, localized_fields=None,
        # labels=None, help_texts=None, error_messages=None,
        # min_num=None, validate_min=False, field_classes=None
    )
    

     

  2. So now create a view for inline model form

    in view.py, create ProductCreate view

    from django.forms import modelformset_factory
    from django.shortcuts import render, get_object_or_404
    from django.views.generic import UpdateView, ListView, CreateView
    from django.shortcuts import redirect
    from django.urls import reverse
    
    from .models import Product
    from .forms import ProductForm, ProductMetaInlineFormset
    
    
    class ProductCreateView(CreateView):
        form_class = ProductForm
        template_name = 'product/product_form.html'
    
        def get_context_data(self, **kwargs):
            context = super(ProductCreateView, self).get_context_data(**kwargs)
    
            context['product_meta_formset'] = ProductMetaInlineFormset()
            return context
    
        def post(self, request, *args, **kwargs):
            self.object = None
            form_class = self.get_form_class()
            form = self.get_form(form_class)
            product_meta_formset = ProductMetaInlineFormset(self.request.POST)
            if form.is_valid() and product_meta_formset.is_valid():
                return self.form_valid(form, product_meta_formset)
            else:
                return self.form_invalid(form, product_meta_formset)
    
        def form_valid(self, form, product_meta_formset):
            self.object = form.save(commit=False)
            self.object.save()
            # saving ProductMeta Instances
            product_metas = product_meta_formset.save(commit=False)
            for meta in product_metas:
                meta.product = self.object
                meta.save()
            return redirect(reverse("product:product_list"))
    
        def form_invalid(self, form, product_meta_formset):
            return self.render_to_response(
                self.get_context_data(form=form,
                                      product_meta_formset=product_meta_formset
                                      )
            )
  3. Attach view to URL in Django

    in urls.py file

    from django.urls import path
    
    from .views import ProductListView, ProductCreateView
    
    app_name = 'product'
    urlpatterns = [
        # ...
        path('products', ProductListView.as_view(), name="product_list"),
        path('products/create', ProductCreateView.as_view(), name="product_form"),
        # ...
    ]
  4. Template view

    create product/product_form.html template

    <div class="container mt-4">
        <form method="post">
            {% csrf_token %}
            <div class="card">
                <div class="card-header">
                    <h4>Create Product</h4>
                </div>
                <div class="card-body">
                    {{ form.non_form_errors }}
                    {{ form.as_p }}
                    <h5 class="text-info">Add Product Metas</h5>
                    {{ product_meta_formset.non_form_errors }}
                    {{ product_meta_formset.management_form }}
                    {% for form in product_meta_formset %}
                    <div class="d-flex py-1 inline {{ product_meta_formset.prefix }}">
                        <div>{{form.name.label}}: {{ form.name }}</div>
                        <div class="ml-4">{{form.value.label}}: {{ form.value }}</div>
                        {% if product_meta_formset.can_delete %}
                            <div class="ml-4">{{ form.DELETE }} {{ form.DELETE.label }}</div>
                        {% endif %}
                    </div>
                    {% endfor %}
                </div>
            </div>
            <div class="mt-3 mb-5">
                <button type="submit" class="px-5 btn btn-info">Submit</button>
            </div>
        </form>
    </div>
  5. Checkout UI view

    formfactory

Related posts

How to work with django ajax requests ?

Sajal Mia

How to create Django form?

Sajal Mia

How to make pure javascript XmlHttpRequest or fetch request for get or post data in Django

Sajal Mia

How to create a virtual environment for Django?

Sajal Mia

How to render Django form individual fields manually?

Sajal Mia

How to optimize your Django application for more speed with ORM?

Sajal Mia

10 comments

psedits 12/07/2021 at 7:37 PM

excellent post

zortilonrel 12/09/2021 at 3:05 PM

Wonderful website. Lots of useful info here. I’m sending it to several friends ans also sharing in delicious. And certainly, thanks for your effort!

Roseanna 07/11/2021 at 9:52 PM

I like what you guys tend to be up too. Such clever work and coverage!

Keep up the wonderful works guys I’ve included you guys to my personal blogroll.

Arnold 11/11/2021 at 7:27 PM

Hi there, I enjoy reading all of your article post.
I wanted to write a little comment to support you.

Kindra 25/11/2021 at 3:36 AM

Appreciate this post. Let me try it out.

Justina 27/11/2021 at 3:10 AM

This is the perfect web site for anybody who wishes to find out about
this topic. You understand so much its almost tough to argue with you (not that I personally would want
to…HaHa). You certainly put a new spin on a subject which
has been discussed for years. Wonderful stuff, just excellent!

judi slot online 10/12/2021 at 6:05 AM

Awesome blog article.Really thank you! Fantastic.

Marylou 11/12/2021 at 4:16 AM

Pretty part of content. I simply stumbled upon your web site and in accession capital
to claim that I get actually enjoyed account
your blog posts. Anyway I’ll be subscribing to your augment
or even I achievement you get entry to constantly fast.

Refugio 23/12/2021 at 4:24 AM

There is noticeably a bundle to find out about this. I assume you made certain good points in features also.

Harold Osgoode 23/12/2021 at 8:22 PM

Some really interesting information, well written and generally user pleasant.

Comments are closed.