[Answered ]-Django Dynamically Add Forms Based On Key Value Pairs List

1👍

For those that might come across this, here is my current solution (also open to improvements):

forms.py

class ItemAspectForm(forms.ModelForm):
    class Meta:
        model = ItemAspect
        exclude = ("item",)

views.py

class ItemAspectCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
    model = ItemAspectForm
    form_class = ItemAspectForm
    template_name = "inventory/item_aspect_form.html"
    success_message = _("Item aspect successfully created")

    def get_context_data(self, **kwargs):
        item = Item.objects.get(id=self.kwargs["id"])
        aspects = [Aspect(**aspect) for aspect in get_item_aspects_for_category(item)["aspects"]]
        context = super().get_context_data()
        ItemAspectFormSet = modelformset_factory(
            model=ItemAspect,
            form=ItemAspectForm,
            can_delete=True,
            extra=len(aspects)
        )
        if self.request.POST:
            context["formset"] = ItemAspectFormSet(self.request.POST)
        else:
            context["formset"] = ItemAspectFormSet()
            for aspect, form in zip(aspects, context["formset"]):
                if aspect.has_values:
                    form.fields["value"] = forms.ChoiceField(
                        choices=((value, value) for value in aspect.values)
                    )

                form.fields["value"].required = aspect.is_required
                form.fields["value"].label = aspect.name
                form.fields["name"].initial = aspect.name
                form.fields["name"].widget = forms.HiddenInput()
        return context

    def form_valid(self, form):
        assert (
            self.request.user.is_authenticated
        )  # for mypy to know that the user is authenticated
        context = self.get_context_data()
        formset = context["formset"]
        item = Item.objects.get(id=self.kwargs["id"])
        if formset.is_valid():
            aspect_forms = formset.save(commit=False)
            for aspect_form in aspect_forms:
                aspect_form.item = item
                aspect_form.save()
        return super().form_valid(form)


item_aspects_create = ItemAspectCreateView.as_view()
👤nertz

Leave a comment