Django form dynamically created fields miss from cleaned_data

I'm trying to implement dynamic fields in ModelForm using AJAX requests. I have a cameras_num custom field as IntegerField. Once user picks value AJAX passes cameras_num field's value to ModelForm with kwargs and generates forms.ModelChoiceField with names camera_{number} ("camera_1", "camera_2" ... "camera_3"). However when form submits form.data contains all "cameras" (lets say {"camera_1": [1], "camera_2": [2]}) while form.cleaned_data contains only one camera ("camera_1").

class ConfigurationForm(forms.ModelForm):
    def __init__(self, *args, **kwargs):
        cameras_qty = kwargs.pop('cameras_qty', 1)
        super(ConfigurationForm, self).__init__(*args, **kwargs)

        if cameras_qty:
            for camera_num in range(1, cameras_qty+1):
                self.fields[f"camera_{camera_num}"] = forms.ModelChoiceField(
                    label=f"Camera {camera_num}",
                    queryset=models.Camera.objects.all()
                )

    cameras_num = forms.IntegerField(
        widget=forms.Select(choices=[(i,i) for i in range(1, 4)]),
        initial=1
    )

view.py:

def create_device_view(request):
    if request.method == "POST":
        device_config_form = forms.ConfigurationForm(request.POST)
        # here device_config_form.data contains all "cameras"
        if device_config_form.is_valid():
            # here only "camera_1" exists in device_config_form.cleaned_data
            device_config_form.save()
            return redirect(reverse("device_list", kwargs={"status": "all"}))
    else:
        device_config_form = forms.ConfigurationForm()
        if is_ajax(request):
            # cameras
            cameras_qty = request.GET.get("cameras_qty")
            if cameras_qty and isinstance(cameras_qty, str):
                cameras_data = []
                # passing cameras qty received from GET parameters
                device_config_form = forms.ConfigurationForm(cameras_qty=int(cameras_qty))
                for field_name in device_config_form.fields.keys():
                    if field_name.startswith("camera_"):
                        camera_field = (
                            device_config_form[field_name].label_tag(),
                            str(device_config_form[field_name])
                            )
                        cameras_data.append(camera_field)
                return JsonResponse(
                    data={"success": True, "cameras": cameras_data},
                    safe=False
                )
                
    return render(
        request,
        "production/device_create.html",
        {"device_config_form": device_config_form})
Back to Top