Django - Как сделать динамические поля на форме Quizz App

Я начал делать систему викторины с Django и я использую Django Template, чтобы показать некоторые вопросы случайным образом на каждом видео.

Я могу сделать это без валидации форм, но не уверен, что это правильно...

На самом деле я только что установил имплементацию вопросов (администратор может добавлять вопросы к каждому видео, и это работает хорошо), так что модель выглядит так:

class Question(models.Model):
    class TypeChoices(models.TextChoices):
        SINGLE = "single"
        MULTIPLE = "multiple"

    uid = models.UUIDField(default=uuid.uuid4, primary_key=True)
    playlist_media = models.ForeignKey(PlaylistMedia, on_delete=CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    text = models.CharField(max_length=255)
    type = models.CharField(
        max_length=10, choices=TypeChoices.choices, default=TypeChoices.SINGLE
    )
    options = ArrayField(models.CharField(max_length=255))
    responses = ArrayField(models.CharField(max_length=255))

Так как тип вопросов может быть "одиночный" или "множественный", шаблон может показывать радио или флажки в зависимости от типа.

Вот пример одного вопроса с типом single: enter image description here

Вот еще один пример с множественным типом: enter image description here

Мой вопрос: Как я могу создать динамическую форму? Потому что если я создам простую форму (с помощью forms.py), я не буду знать, сколько полей пользователь может отправить. Потому что у него может быть 1 вопрос или 2 или 3 (максимум).

примечание: даже если тип один или несколько, "ответы" всегда представляют собой список.

Вот шаблон на всякий случай, чтобы вы знали, как это будет:

{% if questions %}
<div class="is-size-4 has-text-weight-medium mb-4 ">
  <span class="">Quizz</span>
</div>

<form action="{% url 'learning-public-media' person_id=person.uid playlist_media_id=playlist_media.uid %}" method="POST">
  {% csrf_token %}
  <div class="is-flex is-flex-direction-column mb-2">

    {% for question in questions %}
      <div class="mb-2 is-size-5 ">
        <span>{{ question.text }}</span>
      </div>
      {% if question.type == 'single' %}
        <div class="my-1">
          {% for option in question.options %}
            <label class="radio m-1" >
              <input type="radio" name="{{ question.uid }}" value="{{ option }}" required {% if media.done %}
                disabled {% endif %} {% if media.done and option in question.responses %} checked {% endif %} 
              />
              {{ option }}
            </label>
            {% if media.done and option in question.responses %}
              <img class="mx-2" src="{% static 'images/icons/checked.png' %}" width="16" height="16"/>
            {% endif %}
          {% endfor %}
        </div>
      {% else %}
        <div class="is-flex is-flex-direction-column">
          {% for option in question.options %}
            <div class="is-flex is-flex-direction-row is-align-items-center">
              <label class="checkbox my-1">
                <input type="checkbox" name="{{ question.uid }}" value="{{ option }}" {% if media.done %}
                      disabled {% endif %} {% if media.done and option in question.responses %}
                      checked {% endif %} />
                {{ option }}

              </label>
              {% if media.done and option in question.responses %}
                <img class="ml-2" src="{% static 'images/icons/checked.png' %}" width="16" height="16"/>
              {% endif %}
            </div>

          {% endfor %}
        </div>
      {% endif %}
    {% endfor %}

  </div>
  <div class="mt-4">
    <button class="button is-primary" {% if media.done %} disabled {% endif %}>{% if media.done %} Question
      validée {% else %} Valider {% endif %}
    </button>
  </div>
</form>
 {% endif %}

В представлении я просто принимаю POST запрос, но я еще не проверяю форму, потому что я не знаю, как это сделать с моим типом формы:

if request.method == "POST":
    person_playlist_media.done_at = timezone.now()
    person_playlist_media.save()

    from apps.learning.tasks import update_analytics_person_playlist_media_task

    update_analytics_person_playlist_media_task.delay(person_playlist_media.uid)

    try:
        next_media = PlaylistMedia.objects.get(
            playlist=account_playlist.playlist, position=playlist_media.position + 1
        )
        return redirect(
            "learning-public-media",
            person_id=person.uid,
            playlist_media_id=next_media.uid,
        )
    except PlaylistMedia.DoesNotExist:
        return redirect(
            "learning-public-playlist",
            person_id=person.uid,
            playlist_id=account_playlist.playlist.uid,
        )

return render(request, "learning/media/index.html", context=context)
Вернуться на верх