1

I am working on English language test application. There are questions and 4 possible answers for each question. Only one answer is correct. Here are the models:

class EnglishTestQuestion(AbstractDatetimeModel):
    text = models.CharField(max_length=255, verbose_name=u"Question text")

class EnglishTestAnswerVariants(models.Model):
    question = models.ForeignKey(EnglishTestQuestion, verbose_name=_(u"question"), related_name='Variants')
    text = models.CharField(max_length=255, verbose_name=u"Text")
    is_correct = models.BooleanField(_(u"Is correct"), default=False)

class EnglishTestAnswer(AbstractDatetimeModel):
    user = models.ForeignKey(User, blank=True, null=True, verbose_name=u"user")
    question = models.ForeignKey(EnglishTestQuestion, blank=False, verbose_name=u"question")
    answer = models.ForeignKey(EnglishTestAnswerVariants, verbose_name=u"answer")

Here is the view. I create a form for each question and pass initial data. Question field gets initial data, but Answer field ignores it and displays all answers,:

def english_test(request):
    questions = EnglishTestQuestion.objects.all()
    QuestionFormSet = formset_factory(form=EnglishTestForm, max_num=questions.count())
    formset = QuestionFormSet(initial=[{
                                           'question': x,
                                           'answer': EnglishTestAnswerVariants.objects.filter(question=x)
                                       } for x in questions])

    return render(request, 'testing/english_test.html', {"questions": questions, "question_formset": formset})

But it should display for each question only those answers which connected via Foreign Key.

Here is form:

class EnglishTestForm(forms.ModelForm):

    class Meta:
        model = EnglishTestAnswer
        fields = '__all__'
        widgets = {
            'answer': forms.RadioSelect()
        }

How to pass in Answer field only those answers, which are connected with question by FK?

Alex Morozov
  • 5,823
  • 24
  • 28
belek
  • 907
  • 9
  • 35

1 Answers1

2

The initial argument passes the initial values for the fields, not the available options for those fields. In your case you could tweak your EnglishTestForm.answer field's queryset dynamically:

class EnglishTestForm(forms.ModelForm):
    class Meta:
        model = EnglishTestAnswer
        fields = '__all__'
        widgets = {
            'answer': forms.RadioSelect()
        }

    def __init__(self, *args, **kwargs):
        super(EnglishTestForm, self).__init__(*args, **kwargs)
        question = self.initial.get('question')
        if question:
            self.fields['answer'].queryset = question.Variants.all()

P.S.: Actually you have a security problem: a malicious user could forge your formset values, for example, making four forms with the same question id and all the possible answer ids. As you blindly save those forms, then, depending on your method of calculation, it may cause the false positive results of the test. Just to warn you.

Alex Morozov
  • 5,823
  • 24
  • 28