Advanced Usage of Django Crispy Formset Modal
Django Crispy Formset Modal is not limited to basic usage. It provides additional features that make it suitable for more complex use-cases. This section covers some of these advanced features and demonstrates how to apply them.
Multiple Inline Formsets
Django Crispy Formset Modal allows you to define a master form with multiple inline formsets. For example, consider a scenario where you want to register an invoice that includes not only multiple items but also multiple payment terms.
To achieve this, you would define additional models
, forms
, and inline formsets
for the payment terms. Here's an example:
# Models
class PaymentTerm(models.Model):
invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE)
due_date = models.DateField()
amount = models.DecimalField(max_digits=10, decimal_places=2)
# Forms
class PaymentTermForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = ModalEditFormHelper()
self.helper.layout = ModalEditLayout(
"due_date",
"amount",
)
class Meta:
model = PaymentTerm
fields = "__all__"
# Inline Formset
class PaymentTermInline(InlineFormSetFactory):
model = PaymentTerm
form_class = PaymentTermForm
fields = ["due_date", "amount"]
factory_kwargs = {"extra": 0}
Then, in your view
, you would add this additional inline
formset
to the list of inlines
:
class CreateInvoiceView(CreateWithInlinesView):
model = Invoice
inlines = [InvoiceItemInline, PaymentTermInline]
form_class = InvoiceForm
In your form layout, you would include a ModalEditFormsetLayout
for this additional inline formset:
class InvoiceForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.helper = FormHelper()
self.helper.layout = Layout(
Row(Column("invoice_number"), Column("date")),
"client",
Fieldset(
"Items",
ModalEditFormsetLayout(
"InvoiceItemInline",
list_display=["description", "quantity", "unit_price"],
),
),
Fieldset(
"Payment Terms",
ModalEditFormsetLayout(
"PaymentTermInline",
list_display=["due_date", "amount"],
),
),
Submit("submit", "Save", css_class="btn btn-primary float-right"),
)
class Meta:
model = Invoice
fields = "__all__"
See this example in the online demo.
Column Summarizing
Django Crispy Formset Modal allows you to define numeric fields for totaling at the footer of the corresponding HTML table. This is useful when you want to display the total amount for specific fields.
For instance, in the InvoiceItemForm
, if you want to display the total amount for the quantity and unit_price fields, you would define sum_columns
in your ModalEditFormsetLayout
:
Fieldset(
"Items",
ModalEditFormsetLayout(
"InvoiceItemInline",
list_display=["description", "quantity", "unit_price"],
sum_columns=["quantity", "unit_price"],
),
),
This configuration would add a row at the bottom of the table that displays the total quantity and unit_price for all items in the formset. The total is dynamically updated as the values in the formset change.
Mass Deletion
Django Crispy Formset Modal supports the mass deletion of records from the HTML table. It generates a column with checkboxes for each row in the table. These checkboxes can be selected individually or all at once, and upon pressing the delete button, all selected records are removed. This feature does not require any additional configuration.
With these advanced features, Django Crispy Formset Modal offers flexible and powerful solutions for managing complex formsets in your Django projects. In the next section, we will cover customization options and how to adapt the package to fit your specific needs.
Recreate all formsets
Useful when you are using htmx
and you want to recreate all formsets after a swap.
if (typeof window.crispyFormsetModal !== "undefined") {
window.crispyFormsetModal.refresh();
}
Events
Django Crispy Formset Modal provides two events that you can utilize to perform additional actions when forms are added or removed from the formset. These events are:
-
onFormAdded
: This event is triggered whenever a new form is added to the formset. -
onFormDeleted
: This event is triggered whenever an existing form is removed from the formset. -
onModalFormOpened
: This event is triggered whenever the modal form is opened. -
onModalFormClosed
: This event is triggered whenever the modal form is closed.
You can leverage these events to execute custom JavaScript code in response to forms being added or removed. For instance, you could use these events to update the total amount on an invoice form whenever a new line item is added or an existing one is deleted.
Here's an example of how you can attach event listeners to these events:
document.addEventListener("DOMContentLoaded", function () {
if (typeof window.crispyFormsetModal !== "undefined") {
window.crispyFormsetModal.onFormAdded = function (event) {
// Your custom code to handle form addition
// For example, you could update the total amount here
};
window.crispyFormsetModal.onFormDeleted = function (event) {
// Your custom code to handle form removal
// For example, you could update the total amount here
};
window.crispyFormsetModal.onModalFormOpened = function (modalForm) {
// Your custom code to handle modal form opened
};
window.crispyFormsetModal.onModalFormClosed = function (modalForm) {
// Your custom code to handle modal form closed
};
}
});
In the example above, we first check if window.crispyFormsetModal
exists, as it may not be available in certain scenarios. If it exists, we assign functions to the onFormAdded
and onFormDeleted
properties to handle the form addition and removal events, respectively. You can replace the comments with your custom logic to update the total amount or perform any other actions you need.