Django inline formset won't save form appended via JS

I'm trying to create page where "parent" and related object may be updated. Due to some specific business logic "child" form has specific couple of fields where only one of them may be selected. So when option selected JS issues a GET request to get the updated form. The problem is: the form being fetched with initial values and when formset.save() being called the form's cleaned_data turns empty {}.

The things I've checked:

  1. Formset.management_form in tact;
  2. All prefixes correct;
  3. Formset.data looks good;

If I change any data of form inserted dynamically and submit it saves as expected. So the problem seems to be how formsets utilize form.has_changed() logic.

This won't work as well:

class CustomFormset(forms.BaseInlineFormSet):
    for form in self.forms:
        form.empty_permitted = False

A bit of code may be helpful:

class ParentForm(forms.ModelForm):
    title = forms.CharField()
    description = forms.CharField()

class ChildForm(forms.ModelForm):
    item = forms.ModelChoiceField()
    item_type = forms.ModelChoiceField()
    # ---------- One of these fields to be selected

ChildrenInlineFormset = inlineformset_factory(
        models.Parent,
        models.Child,
        form=ChildForm,
        formset=CustomFormset,
        min_num=1,
        max_num=50,
        extra=0,
        can_delete=True
        )

VIEW:

@require_http_methods(["GET", "POST"])
def parent_update_view(request, pk):

    if request.method == "POST":
        
        parent = get_object_or_404(models.Parent, pk=pk)
        parent_form = forms.ParentForm(request.POST, instance=parent)
        child_item_formset = forms.ChildInlineFormset(
            request.POST,
            instance=parent
            )
        
        if parent_form.is_valid() and child_item_formset.is_valid():
            with transaction.atomic():
                parent_form.save()
                child_item_formset.save()

            return redirect(reverse("parent_detail", kwargs={"pk": parent.pk}))
    
    else:
        parent = get_object_or_404(models.Parent, pk=pk)
        parent_form = forms.ParentForm(instance=parent)
        child_item_formset = forms.ChildInlineFormset(
            request.GET or None,
            instance=parent
            )
        
    return render(request, "parent_update.html", 
        {
            "parent_form: parent_form,
            "child_item_formset": child_item_formset
            }
        )

Debugging log show raw data:

FORMSET DATA:

<QueryDict: {
    'csrfmiddlewaretoken': ['token_str'], 
    'name': ['sample title'], 
    'description': [''], 
    'items-TOTAL_FORMS': ['2'], 
    'items-INITIAL_FORMS': ['1'], 
    'items-MIN_NUM_FORMS': ['1'], 
    'items-MAX_NUM_FORMS': ['50'], 
    'items-0-id': ['65'], 
    'items-0-parent': ['8'], 
    'items-0-item': ['322'], 
    'items-0-item_type': [''], 
    'items-0-quantity': ['1'], 
    'items-1-id': [''], 
    'items-1-parent': ['8'], 
    'items-1-item': [''], 
    'items-1-item_type': ['26'], 
    'items-1-quantity': ['1']
}>

CLEANED DATA

[ 
   {
    'item': <Item: Object(10)>, 
    'item_type': None, 
    'quantity': 1, 
    'id': <Child: 'sample title' / None>, 
    'DELETE': False, 
    'parent': <Parent: sample title>
    }, 
    # ----- second form data ---------- 
    {}
]

Also second_form.has_changed() --> False

Would appreciate any idea to solve this problem

Вернуться на верх