1

我正在用 Django 构建一个简单的问答应用程序。我的简化模型是:

class Question(models.Model):
    question_text = models.TextField('Question', max_length=256)

class AnswerChoice(models.Model):
    choice_text = models.CharField('Choice', max_length=32)
    question = models.ForeignKey(Question)
    is_correct = models.BooleanField(default=False)

对于上面的两个模型,我有两个ModelForms (QuestionFormAnswerChoiceForm)。

现在,我在 HTML 页面上显示 aQuestionForm和 4 AnswerChoiceForms,用于编辑问题并为问题添加 4 个答案选项。我想确保用户将一个答案标记为“正确”。

我的视图功能是:

def edit_question(request):
    if request.method == 'POST':
        question_form = QuestionForm(request.POST)
        choice_forms = [AnswerChoiceForm(request.POST, prefix=str(i))
                        for i in xrange(4)]
        if all(c.is_valid() for c in choice_forms) and question_form.is_valid():
            choices = [c.save(commit=False) for c in choice_forms]
            question = question_form.save()
            for c in choices:
                c.question = question
                c.save()
            return HttpResponseRedirect(...) # show the question just added
     # ...

现在,我想验证4 个选项中的一个是否被标记为正确。我可以在edit_question上面的视图函数中进行此检查,但不知何故这似乎有点“错误”:我正在将核心逻辑添加到我并不完全满意的视图函数中。

有没有办法在我的QuestionAnswerChoice模型中或在模型表单的定义中进行此验证?

我没有在上面提供完整的最小代码,希望显示的代码量足够并且不会太长。如果您需要查看更多代码,请询问,我将编辑这篇文章。

4

2 回答 2

2

这里的问题是您没有使用表单集作为答案表单。您应该:它们不仅比单独实例化四个表单更笨拙,而且它们具有clean()专门用于跨子表单验证的方法,而不是按表单进行验证。像这样的东西:

class AnswerFormSet(forms.models.BaseInlineFormSet):
     def clean(self):
        correct_count = sum([form.cleaned_data['is_correct'] for form in self.forms])
        if correct_count != 1:
            raise forms.ValidationError('Exactly one answer must be marked as correct')

在视图中你会这样做:

def edit_question(request):
    AnswerFormset = forms.models.inlineformset_factory(
         Question, Answer, formset=AnswerFormSet, extra=4, max_num=4)
    if request.method == 'POST':
        question = Question()
        question_form = QuestionForm(request.POST, instance=question)
        answer_formset = AnswerFormset(request.POST, instance=question)
        # Check these separately to avoid short-circuiting
        question_valid = question_form.is_valid()
        answer_valid = answer_formset.is_valid()
        if question_valid and answer_valid:
            question_form.save()
            # No need to add new question as it was already set as the instance above
            answer_formset.save()
        # etc
于 2013-09-12T08:06:12.823 回答
0

一种选择如下:

class Question(models.Model):
    question_text = models.TextField('Question', max_length=256)
    def validate_answers(obj):
     if obj.answerchoice_set.filter(is_correct=True).count()==1
       #All well
       return True
     else:
       #delete question and answers if you wish or request for change
       return False

但是您应该记住,这将在保存所有内容后检查您的答案是否有效。然后,如果您愿意,您可以删除您的问题或答案。

def edit_question(request):
  #your usual code
  return (HttpResponseRedirect(...) if question.validate_answers() else  HttpResponseRedirect(...))
于 2013-09-12T07:26:42.943 回答