parts/django/docs/topics/forms/formsets.txt
changeset 307 c6bca38c1cbf
equal deleted inserted replaced
306:5ff1fc726848 307:c6bca38c1cbf
       
     1 .. _formsets:
       
     2 
       
     3 Formsets
       
     4 ========
       
     5 
       
     6 A formset is a layer of abstraction to working with multiple forms on the same
       
     7 page. It can be best compared to a data grid. Let's say you have the following
       
     8 form::
       
     9 
       
    10     >>> from django import forms
       
    11     >>> class ArticleForm(forms.Form):
       
    12     ...     title = forms.CharField()
       
    13     ...     pub_date = forms.DateField()
       
    14 
       
    15 You might want to allow the user to create several articles at once. To create
       
    16 a formset out of an ``ArticleForm`` you would do::
       
    17 
       
    18     >>> from django.forms.formsets import formset_factory
       
    19     >>> ArticleFormSet = formset_factory(ArticleForm)
       
    20 
       
    21 You now have created a formset named ``ArticleFormSet``. The formset gives you
       
    22 the ability to iterate over the forms in the formset and display them as you
       
    23 would with a regular form::
       
    24 
       
    25     >>> formset = ArticleFormSet()
       
    26     >>> for form in formset.forms:
       
    27     ...     print form.as_table()
       
    28     <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
       
    29     <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
       
    30 
       
    31 As you can see it only displayed one empty form. The number of empty forms
       
    32 that is displayed is controlled by the ``extra`` parameter. By default,
       
    33 ``formset_factory`` defines one extra form; the following example will
       
    34 display two blank forms::
       
    35 
       
    36     >>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
       
    37 
       
    38 Using initial data with a formset
       
    39 ---------------------------------
       
    40 
       
    41 Initial data is what drives the main usability of a formset. As shown above
       
    42 you can define the number of extra forms. What this means is that you are
       
    43 telling the formset how many additional forms to show in addition to the
       
    44 number of forms it generates from the initial data. Lets take a look at an
       
    45 example::
       
    46 
       
    47     >>> ArticleFormSet = formset_factory(ArticleForm, extra=2)
       
    48     >>> formset = ArticleFormSet(initial=[
       
    49     ...     {'title': u'Django is now open source',
       
    50     ...      'pub_date': datetime.date.today()},
       
    51     ... ])
       
    52 
       
    53     >>> for form in formset.forms:
       
    54     ...     print form.as_table()
       
    55     <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Django is now open source" id="id_form-0-title" /></td></tr>
       
    56     <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-12" id="id_form-0-pub_date" /></td></tr>
       
    57     <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" id="id_form-1-title" /></td></tr>
       
    58     <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" id="id_form-1-pub_date" /></td></tr>
       
    59     <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
       
    60     <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
       
    61 
       
    62 There are now a total of three forms showing above. One for the initial data
       
    63 that was passed in and two extra forms. Also note that we are passing in a
       
    64 list of dictionaries as the initial data.
       
    65 
       
    66 .. seealso::
       
    67 
       
    68     :ref:`Creating formsets from models with model formsets <model-formsets>`.
       
    69 
       
    70 .. _formsets-max-num:
       
    71 
       
    72 Limiting the maximum number of forms
       
    73 ------------------------------------
       
    74 
       
    75 The ``max_num`` parameter to ``formset_factory`` gives you the ability to
       
    76 limit the maximum number of empty forms the formset will display::
       
    77 
       
    78     >>> ArticleFormSet = formset_factory(ArticleForm, extra=2, max_num=1)
       
    79     >>> formset = ArticleFormset()
       
    80     >>> for form in formset.forms:
       
    81     ...     print form.as_table()
       
    82     <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
       
    83     <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
       
    84 
       
    85 .. versionchanged:: 1.2
       
    86 
       
    87 If the value of ``max_num`` is greater than the number of existing
       
    88 objects, up to ``extra`` additional blank forms will be added to the formset,
       
    89 so long as the total number of forms does not exceed ``max_num``.
       
    90 
       
    91 A ``max_num`` value of ``None`` (the default) puts no limit on the number of
       
    92 forms displayed. Please note that the default value of ``max_num`` was changed
       
    93 from ``0`` to ``None`` in version 1.2 to allow ``0`` as a valid value.
       
    94 
       
    95 Formset validation
       
    96 ------------------
       
    97 
       
    98 Validation with a formset is almost identical to a regular ``Form``. There is
       
    99 an ``is_valid`` method on the formset to provide a convenient way to validate
       
   100 all forms in the formset::
       
   101 
       
   102     >>> ArticleFormSet = formset_factory(ArticleForm)
       
   103     >>> formset = ArticleFormSet({})
       
   104     >>> formset.is_valid()
       
   105     True
       
   106 
       
   107 We passed in no data to the formset which is resulting in a valid form. The
       
   108 formset is smart enough to ignore extra forms that were not changed. If we
       
   109 provide an invalid article::
       
   110 
       
   111     >>> data = {
       
   112     ...     'form-TOTAL_FORMS': u'2',
       
   113     ...     'form-INITIAL_FORMS': u'0',
       
   114     ...     'form-MAX_NUM_FORMS': u'',
       
   115     ...     'form-0-title': u'Test',
       
   116     ...     'form-0-pub_date': u'16 June 1904',
       
   117     ...     'form-1-title': u'Test',
       
   118     ...     'form-1-pub_date': u'', # <-- this date is missing but required
       
   119     ... }
       
   120     >>> formset = ArticleFormSet(data)
       
   121     >>> formset.is_valid()
       
   122     False
       
   123     >>> formset.errors
       
   124     [{}, {'pub_date': [u'This field is required.']}]
       
   125 
       
   126 As we can see, ``formset.errors`` is a list whose entries correspond to the
       
   127 forms in the formset. Validation was performed for each of the two forms, and
       
   128 the expected error message appears for the second item.
       
   129 
       
   130 .. _understanding-the-managementform:
       
   131 
       
   132 Understanding the ManagementForm
       
   133 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   134 
       
   135 You may have noticed the additional data (``form-TOTAL_FORMS``,
       
   136 ``form-INITIAL_FORMS`` and ``form-MAX_NUM_FORMS``) that was required
       
   137 in the formset's data above. This data is required for the
       
   138 ``ManagementForm``. This form is used by the formset to manage the
       
   139 collection of forms contained in the formset. If you don't provide
       
   140 this management data, an exception will be raised::
       
   141 
       
   142     >>> data = {
       
   143     ...     'form-0-title': u'Test',
       
   144     ...     'form-0-pub_date': u'',
       
   145     ... }
       
   146     >>> formset = ArticleFormSet(data)
       
   147     Traceback (most recent call last):
       
   148     ...
       
   149     django.forms.util.ValidationError: [u'ManagementForm data is missing or has been tampered with']
       
   150 
       
   151 It is used to keep track of how many form instances are being displayed. If
       
   152 you are adding new forms via JavaScript, you should increment the count fields
       
   153 in this form as well.
       
   154 
       
   155 The management form is available as an attribute of the formset
       
   156 itself. When rendering a formset in a template, you can include all
       
   157 the management data by rendering ``{{ my_formset.management_form }}``
       
   158 (substituting the name of your formset as appropriate).
       
   159 
       
   160 .. versionadded:: 1.1
       
   161 
       
   162 ``total_form_count`` and ``initial_form_count``
       
   163 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   164 
       
   165 ``BaseFormSet`` has a couple of methods that are closely related to the
       
   166 ``ManagementForm``, ``total_form_count`` and ``initial_form_count``.
       
   167 
       
   168 ``total_form_count`` returns the total number of forms in this formset.
       
   169 ``initial_form_count`` returns the number of forms in the formset that were
       
   170 pre-filled, and is also used to determine how many forms are required. You
       
   171 will probably never need to override either of these methods, so please be
       
   172 sure you understand what they do before doing so.
       
   173 
       
   174 .. versionadded:: 1.2
       
   175 
       
   176 ``empty_form``
       
   177 ~~~~~~~~~~~~~~
       
   178 
       
   179 ``BaseFormSet`` provides an additional attribute ``empty_form`` which returns
       
   180 a form instance with a prefix of ``__prefix__`` for easier use in dynamic
       
   181 forms with JavaScript.
       
   182 
       
   183 Custom formset validation
       
   184 ~~~~~~~~~~~~~~~~~~~~~~~~~
       
   185 
       
   186 A formset has a ``clean`` method similar to the one on a ``Form`` class. This
       
   187 is where you define your own validation that works at the formset level::
       
   188 
       
   189     >>> from django.forms.formsets import BaseFormSet
       
   190 
       
   191     >>> class BaseArticleFormSet(BaseFormSet):
       
   192     ...     def clean(self):
       
   193     ...         """Checks that no two articles have the same title."""
       
   194     ...         if any(self.errors):
       
   195     ...             # Don't bother validating the formset unless each form is valid on its own
       
   196     ...             return
       
   197     ...         titles = []
       
   198     ...         for i in range(0, self.total_form_count()):
       
   199     ...             form = self.forms[i]
       
   200     ...             title = form.cleaned_data['title']
       
   201     ...             if title in titles:
       
   202     ...                 raise forms.ValidationError, "Articles in a set must have distinct titles."
       
   203     ...             titles.append(title)
       
   204 
       
   205     >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
       
   206     >>> data = {
       
   207     ...     'form-TOTAL_FORMS': u'2',
       
   208     ...     'form-INITIAL_FORMS': u'0',
       
   209     ...     'form-MAX_NUM_FORMS': u'',
       
   210     ...     'form-0-title': u'Test',
       
   211     ...     'form-0-pub_date': u'16 June 1904',
       
   212     ...     'form-1-title': u'Test',
       
   213     ...     'form-1-pub_date': u'23 June 1912',
       
   214     ... }
       
   215     >>> formset = ArticleFormSet(data)
       
   216     >>> formset.is_valid()
       
   217     False
       
   218     >>> formset.errors
       
   219     [{}, {}]
       
   220     >>> formset.non_form_errors()
       
   221     [u'Articles in a set must have distinct titles.']
       
   222 
       
   223 The formset ``clean`` method is called after all the ``Form.clean`` methods
       
   224 have been called. The errors will be found using the ``non_form_errors()``
       
   225 method on the formset.
       
   226 
       
   227 Dealing with ordering and deletion of forms
       
   228 -------------------------------------------
       
   229 
       
   230 Common use cases with a formset is dealing with ordering and deletion of the
       
   231 form instances. This has been dealt with for you. The ``formset_factory``
       
   232 provides two optional parameters ``can_order`` and ``can_delete`` that will do
       
   233 the extra work of adding the extra fields and providing simpler ways of
       
   234 getting to that data.
       
   235 
       
   236 ``can_order``
       
   237 ~~~~~~~~~~~~~
       
   238 
       
   239 Default: ``False``
       
   240 
       
   241 Lets create a formset with the ability to order::
       
   242 
       
   243     >>> ArticleFormSet = formset_factory(ArticleForm, can_order=True)
       
   244     >>> formset = ArticleFormSet(initial=[
       
   245     ...     {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
       
   246     ...     {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
       
   247     ... ])
       
   248     >>> for form in formset.forms:
       
   249     ...     print form.as_table()
       
   250     <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
       
   251     <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
       
   252     <tr><th><label for="id_form-0-ORDER">Order:</label></th><td><input type="text" name="form-0-ORDER" value="1" id="id_form-0-ORDER" /></td></tr>
       
   253     <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
       
   254     <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
       
   255     <tr><th><label for="id_form-1-ORDER">Order:</label></th><td><input type="text" name="form-1-ORDER" value="2" id="id_form-1-ORDER" /></td></tr>
       
   256     <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
       
   257     <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
       
   258     <tr><th><label for="id_form-2-ORDER">Order:</label></th><td><input type="text" name="form-2-ORDER" id="id_form-2-ORDER" /></td></tr>
       
   259 
       
   260 This adds an additional field to each form. This new field is named ``ORDER``
       
   261 and is an ``forms.IntegerField``. For the forms that came from the initial
       
   262 data it automatically assigned them a numeric value. Lets look at what will
       
   263 happen when the user changes these values::
       
   264 
       
   265     >>> data = {
       
   266     ...     'form-TOTAL_FORMS': u'3',
       
   267     ...     'form-INITIAL_FORMS': u'2',
       
   268     ...     'form-MAX_NUM_FORMS': u'',
       
   269     ...     'form-0-title': u'Article #1',
       
   270     ...     'form-0-pub_date': u'2008-05-10',
       
   271     ...     'form-0-ORDER': u'2',
       
   272     ...     'form-1-title': u'Article #2',
       
   273     ...     'form-1-pub_date': u'2008-05-11',
       
   274     ...     'form-1-ORDER': u'1',
       
   275     ...     'form-2-title': u'Article #3',
       
   276     ...     'form-2-pub_date': u'2008-05-01',
       
   277     ...     'form-2-ORDER': u'0',
       
   278     ... }
       
   279 
       
   280     >>> formset = ArticleFormSet(data, initial=[
       
   281     ...     {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
       
   282     ...     {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
       
   283     ... ])
       
   284     >>> formset.is_valid()
       
   285     True
       
   286     >>> for form in formset.ordered_forms:
       
   287     ...     print form.cleaned_data
       
   288     {'pub_date': datetime.date(2008, 5, 1), 'ORDER': 0, 'title': u'Article #3'}
       
   289     {'pub_date': datetime.date(2008, 5, 11), 'ORDER': 1, 'title': u'Article #2'}
       
   290     {'pub_date': datetime.date(2008, 5, 10), 'ORDER': 2, 'title': u'Article #1'}
       
   291 
       
   292 ``can_delete``
       
   293 ~~~~~~~~~~~~~~
       
   294 
       
   295 Default: ``False``
       
   296 
       
   297 Lets create a formset with the ability to delete::
       
   298 
       
   299     >>> ArticleFormSet = formset_factory(ArticleForm, can_delete=True)
       
   300     >>> formset = ArticleFormSet(initial=[
       
   301     ...     {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
       
   302     ...     {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
       
   303     ... ])
       
   304     >>> for form in formset.forms:
       
   305     ....    print form.as_table()
       
   306     <input type="hidden" name="form-TOTAL_FORMS" value="3" id="id_form-TOTAL_FORMS" /><input type="hidden" name="form-INITIAL_FORMS" value="2" id="id_form-INITIAL_FORMS" /><input type="hidden" name="form-MAX_NUM_FORMS" id="id_form-MAX_NUM_FORMS" />
       
   307     <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" value="Article #1" id="id_form-0-title" /></td></tr>
       
   308     <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" value="2008-05-10" id="id_form-0-pub_date" /></td></tr>
       
   309     <tr><th><label for="id_form-0-DELETE">Delete:</label></th><td><input type="checkbox" name="form-0-DELETE" id="id_form-0-DELETE" /></td></tr>
       
   310     <tr><th><label for="id_form-1-title">Title:</label></th><td><input type="text" name="form-1-title" value="Article #2" id="id_form-1-title" /></td></tr>
       
   311     <tr><th><label for="id_form-1-pub_date">Pub date:</label></th><td><input type="text" name="form-1-pub_date" value="2008-05-11" id="id_form-1-pub_date" /></td></tr>
       
   312     <tr><th><label for="id_form-1-DELETE">Delete:</label></th><td><input type="checkbox" name="form-1-DELETE" id="id_form-1-DELETE" /></td></tr>
       
   313     <tr><th><label for="id_form-2-title">Title:</label></th><td><input type="text" name="form-2-title" id="id_form-2-title" /></td></tr>
       
   314     <tr><th><label for="id_form-2-pub_date">Pub date:</label></th><td><input type="text" name="form-2-pub_date" id="id_form-2-pub_date" /></td></tr>
       
   315     <tr><th><label for="id_form-2-DELETE">Delete:</label></th><td><input type="checkbox" name="form-2-DELETE" id="id_form-2-DELETE" /></td></tr>
       
   316 
       
   317 Similar to ``can_order`` this adds a new field to each form named ``DELETE``
       
   318 and is a ``forms.BooleanField``. When data comes through marking any of the
       
   319 delete fields you can access them with ``deleted_forms``::
       
   320 
       
   321     >>> data = {
       
   322     ...     'form-TOTAL_FORMS': u'3',
       
   323     ...     'form-INITIAL_FORMS': u'2',
       
   324     ...     'form-MAX_NUM_FORMS': u'',
       
   325     ...     'form-0-title': u'Article #1',
       
   326     ...     'form-0-pub_date': u'2008-05-10',
       
   327     ...     'form-0-DELETE': u'on',
       
   328     ...     'form-1-title': u'Article #2',
       
   329     ...     'form-1-pub_date': u'2008-05-11',
       
   330     ...     'form-1-DELETE': u'',
       
   331     ...     'form-2-title': u'',
       
   332     ...     'form-2-pub_date': u'',
       
   333     ...     'form-2-DELETE': u'',
       
   334     ... }
       
   335 
       
   336     >>> formset = ArticleFormSet(data, initial=[
       
   337     ...     {'title': u'Article #1', 'pub_date': datetime.date(2008, 5, 10)},
       
   338     ...     {'title': u'Article #2', 'pub_date': datetime.date(2008, 5, 11)},
       
   339     ... ])
       
   340     >>> [form.cleaned_data for form in formset.deleted_forms]
       
   341     [{'DELETE': True, 'pub_date': datetime.date(2008, 5, 10), 'title': u'Article #1'}]
       
   342 
       
   343 Adding additional fields to a formset
       
   344 -------------------------------------
       
   345 
       
   346 If you need to add additional fields to the formset this can be easily
       
   347 accomplished. The formset base class provides an ``add_fields`` method. You
       
   348 can simply override this method to add your own fields or even redefine the
       
   349 default fields/attributes of the order and deletion fields::
       
   350 
       
   351     >>> class BaseArticleFormSet(BaseFormSet):
       
   352     ...     def add_fields(self, form, index):
       
   353     ...         super(BaseArticleFormSet, self).add_fields(form, index)
       
   354     ...         form.fields["my_field"] = forms.CharField()
       
   355 
       
   356     >>> ArticleFormSet = formset_factory(ArticleForm, formset=BaseArticleFormSet)
       
   357     >>> formset = ArticleFormSet()
       
   358     >>> for form in formset.forms:
       
   359     ...     print form.as_table()
       
   360     <tr><th><label for="id_form-0-title">Title:</label></th><td><input type="text" name="form-0-title" id="id_form-0-title" /></td></tr>
       
   361     <tr><th><label for="id_form-0-pub_date">Pub date:</label></th><td><input type="text" name="form-0-pub_date" id="id_form-0-pub_date" /></td></tr>
       
   362     <tr><th><label for="id_form-0-my_field">My field:</label></th><td><input type="text" name="form-0-my_field" id="id_form-0-my_field" /></td></tr>
       
   363 
       
   364 Using a formset in views and templates
       
   365 --------------------------------------
       
   366 
       
   367 Using a formset inside a view is as easy as using a regular ``Form`` class.
       
   368 The only thing you will want to be aware of is making sure to use the
       
   369 management form inside the template. Let's look at a sample view:
       
   370 
       
   371 .. code-block:: python
       
   372 
       
   373     def manage_articles(request):
       
   374         ArticleFormSet = formset_factory(ArticleForm)
       
   375         if request.method == 'POST':
       
   376             formset = ArticleFormSet(request.POST, request.FILES)
       
   377             if formset.is_valid():
       
   378                 # do something with the formset.cleaned_data
       
   379                 pass
       
   380         else:
       
   381             formset = ArticleFormSet()
       
   382         return render_to_response('manage_articles.html', {'formset': formset})
       
   383 
       
   384 The ``manage_articles.html`` template might look like this:
       
   385 
       
   386 .. code-block:: html+django
       
   387 
       
   388     <form method="post" action="">
       
   389         {{ formset.management_form }}
       
   390         <table>
       
   391             {% for form in formset.forms %}
       
   392             {{ form }}
       
   393             {% endfor %}
       
   394         </table>
       
   395     </form>
       
   396 
       
   397 However the above can be slightly shortcutted and let the formset itself deal
       
   398 with the management form:
       
   399 
       
   400 .. code-block:: html+django
       
   401 
       
   402     <form method="post" action="">
       
   403         <table>
       
   404             {{ formset }}
       
   405         </table>
       
   406     </form>
       
   407 
       
   408 The above ends up calling the ``as_table`` method on the formset class.
       
   409 
       
   410 Using more than one formset in a view
       
   411 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
       
   412 
       
   413 You are able to use more than one formset in a view if you like. Formsets
       
   414 borrow much of its behavior from forms. With that said you are able to use
       
   415 ``prefix`` to prefix formset form field names with a given value to allow
       
   416 more than one formset to be sent to a view without name clashing. Lets take
       
   417 a look at how this might be accomplished:
       
   418 
       
   419 .. code-block:: python
       
   420 
       
   421     def manage_articles(request):
       
   422         ArticleFormSet = formset_factory(ArticleForm)
       
   423         BookFormSet = formset_factory(BookForm)
       
   424         if request.method == 'POST':
       
   425             article_formset = ArticleFormSet(request.POST, request.FILES, prefix='articles')
       
   426             book_formset = BookFormSet(request.POST, request.FILES, prefix='books')
       
   427             if article_formset.is_valid() and book_formset.is_valid():
       
   428                 # do something with the cleaned_data on the formsets.
       
   429                 pass
       
   430         else:
       
   431             article_formset = ArticleFormSet(prefix='articles')
       
   432             book_formset = BookFormSet(prefix='books')
       
   433         return render_to_response('manage_articles.html', {
       
   434             'article_formset': article_formset,
       
   435             'book_formset': book_formset,
       
   436         })
       
   437 
       
   438 You would then render the formsets as normal. It is important to point out
       
   439 that you need to pass ``prefix`` on both the POST and non-POST cases so that
       
   440 it is rendered and processed correctly.