Django динамически добавляет формы на основе списка пар ключ-значение

Есть ли способ динамически создавать наборы форм на основе ответа API. Это легко сделать на JS, однако, приложение работает под управлением Django's MVT, и я хотел бы создать форму динамически в python.

models.py

class Item(models.Model):
    name = models.CharField(max_length=50)

class ItemAspect(models.Model):
    name = models.CharField(max_length=50)
    value = models.CharField(max_length=50)
    item = models.ForeignKey(Item, on_delete=models.CASCADE)

API resposne:

{
 {
   "key": "Name",
   "value_list": [
       "value0",
        ...
    ]
  },
  ...
}
   

Желаемая форма:

<form>
  ...
  <label for="value-0"> {{ key }}</label>
  <select name="value-0" id="value-0">
      <option value="{{ value_list[0] }}"> {{ value_list[0] }} </option>
      ...
  </select>
  <---! The below would be handled in the view, just adding for context -->
  <input style="display: hidden;" name="name-0" value="{{ key }}">
  ...
</form>

Мое лучшее предположение заключается в том, что это можно сделать с помощью crispy's form_helper в представлении после получения ответа API.

Для тех, кто может столкнуться с этим, вот мое текущее решение (также открытое для улучшений):

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):
        context = self.get_context_data()
        formset = context["formset"]
        if formset.is_valid():
            formset.save()
        return super().form_valid(form)


item_aspects_create = ItemAspectCreateView.as_view()
Вернуться на верх