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()