Configuration
First prepare your Django templates to use a supported HTML structure, and then initialise the formsets using the configuration options to customise how your formset works.
HTML Structure
By default, django-fancy-formset would like you to construct your formset in a specific way:
<div data-formset="{{ formset.prefix }}"> {# Formset container to target #}
{{ formset.management_form }} {# Add the management form #}
<fieldset style="display: none"> {# Add and hide the empty form #}
{{ formset.empty_form.as_p }}
</fieldset>
{% for form in formset %}
<fieldset> {# Each formset form has a container #}
{{ form.as_p }} {# Actual form layout doesn't matter #}
</fieldset>
{% endfor %}
</div>
set a
data-formset="prefix"attribute on the formset container so it can be found byinit()put each form in its own
fieldsetcontainer, as direct children of the formset containeradd a
formset.empty_formin a container as one of the forms, to act as a templateremember to add the
formset.management_formsomewhere
It doesn’t matter what your formset forms look like, just as long as they’re in a container.
If you want to construct your formset differently, you can extend the classes to override the defaults.
Note
All inline style="..." attributes are removed from the empty form container when
it is copied, so you can set style="display: none" on the empty form to hide it.
If you want to add styles to the form container, you should use CSS classes. If you want to hide it in a different way, see options, Events and Extending functionality.
Styling your formset
There is a default stylesheet available which:
Adds some basic fieldset styling to make your form clearer to use
Styles the delete button to hide the form being deleted
Styles the add button
This is available as formset.min.css if you want to use it directly, or
formset.css (or src/formset.scss in github) if you want to use it as a starting
point.
Initialise the formsets
If your formsets follow the expected HTML structure above, you can initialise all of the
formsets on a page at once by calling init() with no arguments.
For example, you can do this in the HTML from the bottom of your body tag:
<script>
formset.init();
</script>
</body>
or once the DOM is ready from your JavaScript bundle:
import { init } from 'django-fancy-formset';
document.addEventListener('DOMContentLoaded', e => {
init();
});
You can also customise which formsets are initialised and how they work by specifying options and targets:
formset.init(options, targets);
Specifying options
You can configure the formsets using an options object - for example:
formset.init(
{
formSelector: 'div.form',
templateSelector: 'div.form.form-template',
allowDeleteAtMin: true
}
);
- options
type: object
- options.formsetSelector
Selector used to target the root formset element. If no target is passed to
init(), the target defaults toquerySelectorAll(options.formsetSelector).Default:
"[data-formset]"- select all DOM elements with adata-formsetattribute
- options.formsetClass
type: Formset
JavaScript class to use for the formset object. Only needed if subclassing the standard Formset class.
Default:
Formset
- options.prefix
Explicit prefix for the formset
By default the prefix will be picked up from an attribute on the root formset element (the attribute
options.prefixAttr, which defaults to"data-formset"). You only need to setprefixif you don’t want to add the attribute to the root formset element.If set, any value in
prefixAttrwill be ignored.Default:
null- prefix will be collected usingprefixAttr
- options.prefixAttr
If
prefixis not set, look for the formset prefix on this attribute of the root formset element.Default:
"data-formset"- the value of the"data-formset"attribute
- options.formSelector
Selector to find all form containers, relative to the formset root element.
Default:
":scope > fieldset"- all direct fieldset children of the formset root
- options.formClass
type: Form
JavaScript class to use when creating a form object. Only needed if subclassing the standard
Formclass.Default:
Form
- options.pkFieldName
Name of the primary key field for the form
Default:
"id"
- options.formsetActiveCss
CSS class name to add to an active formset root element
Useful for restyling interactive formsets with progressive enhancement
Default:
"formset-active"
- options.formAddedCss
CSS class name to add to a form added by the “Add” button
Defaukt:
"added"
- options.formDeletedCss
CSS class name to add to a form marked for deletion
Default:
"deleted"
- options.addButtonLabel
Label for the formset’s add
<button>, appended to the formset rootDefault:
"Add"
- options.addButtonCss
CSS class name for the formset’s add <button>
Default:
"formset-add"
- options.deleteConClosest
Selector used to find the field container ancestor of the delete form field
The delete element for a form will be
<input name="...-DELETE">. We find this element within the form root asdeleteEl, then find its container withdeleteEl.closest(options.deleteConClosest)In default form layouts, this will be:
as_p:<p> ... <input name="...-DELETE"> ... </p>as_div:<div> ... <input name="...-DELETE"> ... </div>as_list:<li> ... <input name="...-DELETE"> ... </li>as_table:<tr> ... <input name="...-DELETE"> ... </tr>
Default:
"p, div, tr, li"
- options.deleteConCss
CSS class to add to the form field’s delete container
This is a convenience to simplify restyling the delete button.
Default:
"formset-delete"
- options.formsetAtMinCss
CSS class name for the formset root when it has the minimum number of active forms
Default:
"formset-at-min"
- options.allowDeleteAtMin
type: bool
Control if forms can be deleted when the formset has the minimum number of forms
Only applies to the delete checkbox; does not affect empty form removal at startup
Default:
false
- options.formsetAtMaxCss
CSS class name for the formset root when it has the maximum number of active forms
Default:
"formset-at-max"
- options.allowAddAtMax
type: bool
Control if forms can be added when the formset has the maximum number of forms
Default:
false
Specifying targets
If not all of your formsets on the page need to be initialised, or if they need different options, you can specify a target as the second argument.
The target can be a selector, or the results of querySelectorAll:
formset.init({}, 'fieldset.formset')
formset.init({}, document.querySelectorAll('fieldset.formset'))