Как заставить Django FormSet принимать m2m, но хранить их как несколько записей FK? - PullRequest
0 голосов
/ 25 сентября 2019

Мне нужно предоставить тест для студентов, но на некоторые вопросы можно получить несколько ответов.

Можно ли создать несколько записей для хранения нескольких ответов вместо использования M2M?

, например, еслистудент, выбирающий A и B для вопроса, будет вести себя следующим образом:

StudentAnwer.objects.create(question=question, answer=answer_a)
StudentAnwer.objects.create(question=question, answer=answer_b)

formsets.py

from django import forms

StudentAnswerFormSet = forms.inlineformset_factory(
    Student,
    StudentAnswer,
    fields=['question', 'answer', ],
    formset=forms.BaseInlineFormSet)

models.py

class Question(BaseModel):
    title = models.CharField(max_length=250)
    is_multiple = models.BooleanField(default=False)

class StudentAnswer(BaseModel):
    student = models.ForeignKey(Student, related_name='answers')
    question = models.ForeignKey(Question, related_name='student_answers')
    answer = models.ForeignKey(Answer, related_name='student_answers')

просмотров.py

from formtools.wizard.views import SessionWizardView

class StudentWizardView(SessionWizardView):
    ...

    def get_answer_form(self, step=None, data=None, files=None):
        ...

        question_list = get_question_list()

        return forms.inlineformset_factory(
            Student,
            StudentAnswer,
            fields=['question', 'answer', ],
            extra=len(question_list),
            formset= forms.BaseInlineFormSet)

    def get_form(self, step=None, data=None, files=None):
        form = super(StudentWizardView, self).get_form(step, data, files)

        # determine the step if not given
        if step is None:
            step = self.steps.current

        if step == self.STEP_ANSWER:
            initial_dict = self.get_form_initial(step)

            prev_form_data = self.get_cleaned_data_for_step(self.STEP_PROFILE)

            form = self.get_answer_form(step, data, files)

            for form_index in range(len(initial_dict.keys())):
                question = initial_dict[form_index]['question']

                answer_list = question.get_answer_list()

                if question.is_multiple:
                    form.forms[form_index].fields['answer'] = ModelMultipleChoiceField(queryset=answer_list,
                                                                                   widget=CheckboxSelectMultiple)
                else:
                    form.forms[form_index].fields['answer'].widget.choices.queryset = answer_list

Я стараюсь избегать M2M, чтобы упростить отображение возможных ответов на вопрос в шаблоне.

{{ wizard.management_form }}
{{ wizard.form.management_form }}

{% for answer_form in wizard.form.forms %}
  {{ answer_form.question }}
  {{ answer_form.answer }}

  {% for hidden in answer_form.hidden_fields %}
    {{ hidden }}
  {% endfor %}
{% endfor %}

1 Ответ

0 голосов
/ 26 сентября 2019

Устранено с помощью необработанного form.data вместо form.cleaned_data, поэтому можно было получить доступ к нескольким значениям для одного и того же поля до того, как они были очищены.

Это рискованно, но вы можете повторить метод очистки только длячасти, которые вы хотите, чтобы он действовал.

Также сделал список настраиваемых флажков:

{% for choice in field.field.choices %}
  <input type="checkbox" id="id_{{ field.html_name }}_{{ forloop.counter }}" name="{{ field.html_name }}" value="{{ choice.id }}"{% if choice.id in field.value %} checked="checked"{% endif %}> {{ choice }}
{% endfor %}

И удалил поле настраиваемой формы, так что все они:

form.forms[form_index].fields['answer'].widget.choices.queryset = answer_list
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...