djangomany-to-manyformset

Django: Prepopulate extra fields in a Formset with a ManyToMany Model


I have two models with a ManyToMany (M2M) relationship. In order to have extra fields on the M2M Model, I defined a through= model. I tried setting up a inlineformset_factory, using parent=ChildModel and model=ParentModel.parent_child.through as described in this thread pendant to inline formsets for many-to-many relations. But it did not solve my issue.

How can I access (i.e. prepopulate) and update the extra fields of the M2M model, when using formsets?

models.py

class ParentModel(models.Model):
    name = model.CharField()
    parent_child = model.ManyToManyField(ChildModel, through='ParentChildModel')


class ChildModel(models.Model):
    name = model.CharField()
    

class ParentChildModel(models.Model):
    parent = models.ForeignKey(ParentModel, on_delete=models.CASCADE)
    child = models.ForeignKey(ChildModel, on_delete=models.CASCADE)
    extra_field_1 = models.CharField()

forms.py

class ChildForm(forms.ModelForm):

    class Meta:
        model = ChildModel
        fields = '__all__'



ChildFormset = modelformset_factory(ChildModel,
                                     form=ChildForm,
                                     extra=0,
                                     can_delete=True,
                                     can_order=True,
                                     )

Solution

  • I found a solution, setting up a ModelFormset on the ChildModel. For the extra field of the ParentChildModel, I defined a field in form.py which I manually populate using the code down below.

    views.py

    # get instances
    parent_instance = Parent.objects.get(id=pk)
    parent_children = parent_instance.parent_child.all()
    parent_child_instance = ParentChildModel.objects.filter(parent=parent_instance)
    
    # initializing & prepopulate forms
    parent_form = ParentForm(request.POST or None, instance=parent_instance)
    child_formset = ChildFormset(request.POST or None, queryset=parent_children)
    for child_form in child_formset:
        child_form.fields['extra_field_1'].initial = parent_child_instance.get(child=child_form.instance).extra_field_1
    

    forms.py

    class ChildForm(forms.ModelForm):
        extra_field_1 = forms.CharField()
    
        class Meta:
            model = ChildModel
            fields = '__all__'
    
    
    ChildFormset = modelformset_factory(ChildModel,
                                        form=ChildForm,
                                        ...
                                        )