We use ModelFormSetView
from django-extra-views for a similar use case. This is not supported by the through
model, but a table with many relationships, in which many relationships with all their attributes are displayed as part of a detailed representation of the underlying model associated with ForeignKey.
It will work for the through
model, simply by providing the through
Model as an attribute of the model ModelFormSetView
. When saving or even earlier, through get_extra_form_kwargs
you will need to set a link to an instance of the main model, which defines the m2m field.
The difficult thing with regular django FormSets (for me) is that it is mainly designed to create new objects, while we only need to display existing objects and modify them. Basically, we need repeating forms filled with raw data, which are saved immediately. You can also delete them.
View
The form
Regular Django ModelForm for your through
model. As here, provide a link to an instance of the model defining the m2m field so that you can assign it before saving.
def __init__(self, *args, user=None, **kwargs): self.user = user super().__init__(*args, **kwargs) def save(self, commit=True): self.instance.owner = self.user return super().save(commit)
Template
<form id="the-matching" method="POST" action="{{ save_url }}" data-session-url="{{ session_url }}"> {% csrf_token %} {{ formset.management_form }} <ul class="match__matches"> {% for form in formset %} {% include 'import_match__match.html' %} {% endfor %} </ul> </form>
In each form (inside import_match__match.html
), you import_match__match.html
over the fields in the usual django way. Here is an example of hidden fields:
{% for field in form %} {% if field.value %} <input type="hidden" name="{{ form.prefix }}-{{ field.name }}" value="{{ field.value }}"/> {% endif %} {% endfor %}
Form processing for the main object:
- you can create two views and send them to both via JS after clicking one "Save" button.
- or you can submit one view (e.g. above) and create a form for the main object explicitly in get () and post (), and then save it when formet_valid is called.
- You can also try to implement both ModelFormsetView and FormView and override all the appropriate methods to handle both instances of the forms (form instance and main form).