Formsets

Sample

  • forms.py:

    from django import forms
    from django.forms.formsets import formset_factory
    
    class AdminProductShopForm(forms.Form):
        sku = forms.CharField(
            widget=forms.TextInput(attrs={
                'readonly': 'readonly',
                'size': 50,
                })
            )
        price = forms.DecimalField()
        sell_in_shop = forms.BooleanField()
    
    AdminProductShopFormSet = formset_factory(AdminProductShopForm, extra=0)
    

    Note:

    • In this example, we have requested that the form set doesn’t display any extra forms i.e. 0.

    • We have made the sku field read only.

  • views.py:

    def admin_shop_products_view(request, shop_slug):
        products = Product.objects.order_by('sku').values('sku')
        product_forms = AdminProductShopFormSet(initial=products)
        return render_to_response(
            'shop/admin_shop_products.html',
            {
                'formset': product_forms,
            },
            context_instance=RequestContext(request)
            )
    

    Note:

    • In this example, the result from the query set is converted to a list of dictionaries by the values method. This is used to initialise the form set.

    • The form is initialised with the initial parameter.

  • Template:

    {% if formset %}
        {{ formset.management_form }}
        <table>
            <tr>
                <th>
                    Product
                </th>
                <th>
                    Price
                </th>
                <th>
                    Sell in Shop
                </th>
            </tr>
            {% for form in formset.forms %}
                <tr>
                    <td>
                        <div class="fieldWrapper">
                            {{ form.sku.errors }}
                            {{ form.sku }}
                        </div>
                    </td>
                    <td>
                        <div class="fieldWrapper">
                            {{ form.price.errors }}
                            {{ form.price }}
                        </div>
                    </td>
                    <td>
                        <div class="fieldWrapper">
                            {{ form.sell_in_shop.errors }}
                            {{ form.sell_in_shop }}
                        </div>
                    </td>
                </tr>
            {% endfor %}
        </table>
    {% endif %}
    

    Note:

    • Don’t miss the management_form (see above).

    • The simplest method for displaying a form set is as follows:

      <form method="post" action="">
          {{ formset.management_form }}
          <table>
              {% for form in formset.forms %}
                  {{ form }}
              {% endfor %}
          </table>
      </form>
      

      … or even …

      <form method="post" action="">
          <table>
              {{ formset }}
          </table>
      </form>
      

Multiple Formsets

Using more than one formset in a view

Use the prefix on both the POST and non-POST cases:

def manage_articles(request):
    ArticleFormSet = formset_factory(ArticleForm)
    BookFormSet = formset_factory(BookForm)
    if request.method == 'POST':
        article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles')
        book_formset = BookFormSet(request.POST, request.FILES, prefix='books')
        if article_formset.is_valid() and book_formset.is_valid():
            # do something with the cleaned_data on the formsets.
    else:
        article_formset = ArticleFormSet(prefix='articles')
        book_formset = BookFormSet(prefix='books')
    return render_to_response('manage_articles.html', {
        'article_formset': article_formset,
        'book_formset': book_formset,
    })

Model

Sample

Django: Initializing a FormSet of custom forms with instances

def edit(request):
    PointFormSet = modelformset_factory(Point, form = PointForm)
    qset = Point.objects.all() #or however your getting your Points to modify
    formset = PointFormset(queryset = qset)
    if request.method == 'POST':
        #deal with posting the data
        formset = PointFormset(request.POST)
        if formset.is_valid():
            #if it is not valid then the "errors" will fall through and be returned
            formset.save()
        return #to your redirect

    context_dict = {'formset':formset,
                    #other context info
                    }

    return render_to_response('your_template.html', context_dict)