Django — Как сделать подсчет очков в приложении для викторины с несколькими попытками

#python #python-3.x #django #django-models #django-views

#python #python-3.x #django #django-модели #django-просмотры

Вопрос:

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

Это настройка моей модели:

 class Quiz(models.Model):
    song = models.ForeignKey(Song, null=True, on_delete=models.CASCADE)
    title = models.CharField(max_length=15)
    slug = models.SlugField(unique=True, max_length=250)
    questions_count = models.IntegerField(default=0)

class Question(models.Model):
    quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
    label = models.CharField(max_length=1000, help_text="Enter the question text that you want displayed")

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    answer = models.CharField(max_length=100)
    is_correct = models.BooleanField('Correct answer', default=False)

class QuizTaker(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
    correct_answers = models.IntegerField(default=0)
    completed = models.BooleanField(default=False)
    attempt_number = models.AutoField(primary_key=True)
  

В моем html тест отображается следующим образом:

 {% for q in question_list %}
  {{q}} <br>
  {% for choice in q.choice_set.all %}
      <input type="radio" name="choice" id="choice{{ forloop.counter }}" value="{{ choice.answer }}">
      <label for="choice{{ forloop.counter }}">{{ choice.answer }}</label><br>
  {% endfor %}
<a class='btn btn-warning save_ans' href="#">Save answer</a>
  

Ответ на каждый вопрос обрабатывается с помощью вызова ajax и отправляется в следующее представление:

  ans_given = []
 def save_ans(request):
      ans = request.GET['ans']
      ans_given.append(ans)
      return HttpResponse(ans)
  

Я подошел к подсчету очков следующим образом:

 ans_correct = []
answers = models.Choice.objects.filter(is_correct=True)

for i in answers:
    scoring['ans_correct'].append(i.answer)

def quiz_results(request, pk):
    score = 0
    quiz = models.Quiz.objects.get(song__pk=pk)
    count = quiz.questions_count

    questions = models.Question.objects.filter(quiz=quiz)
    for i in range(len(questions)):
        if ans_given[i] == ans_correct[i]:
            score  =1

    combined = list(zip(scoring['ans_correct'],scoring['ans_given']))
    return render(request, 'quizzes/quiz_song_result.html', {'score': score, 'combined': combined})
  

И это работает нормально, но только в первый раз. Я хочу разрешить пользователю делать несколько попыток в викторине. После первого раза я получаю list index out of range ошибку, которая, конечно, имеет смысл, потому что она сохранила первые n ответы и добавила n больше в список, в то время как длина ans_correct , конечно, не меняется.

Я пробовал различные способы исправить это, но безрезультатно. Я пытался использовать insert вместо append , но не могу правильно выполнить индексацию. Я пытался помещать ans_given.clear() в начало функции, чтобы каждый раз начинать с чистого списка, но он очищает список после каждого ответа (не после всего теста).

Я также пытался получить ответы, подобные этому:

 for question in questions:
    answer = models.Choice.objects.values_list('answer', flat=True).get(is_correct=True, question=question)
    scoring['ans_correct'].append(answer)
  

А затем делаем подсчет очков аналогичным образом. В этом случае списки имеют, по крайней мере, одинаковую длину, но подсчет очков по-прежнему не работает, и это портит мой шаблон.

Я почти уверен, что для этого есть простое решение, и я просто не вижу этого. Или что есть гораздо лучший способ сделать то, что я хочу сделать … так что, если кто-нибудь может мне помочь, я был бы очень благодарен!

Редактировать: мне удалось решить мою проблему следующим образом (но я все еще жду предложений о том, как подойти к этому по-другому, даже если это означает большую часть переделки).

 ans_user = ans_given[len(ans_given)-len(questions):]
ans_corr = ans_correct[len(ans_given)-len(questions):]

for i in range(len(questions)):
    if ans_user[i] == ans_corr[i]:
        score  =1
  

Комментарии:

1. Разве вы не сохраняете ответ где-нибудь? Как передать значение ans_given quiz_results ?

2. Я просто добавляю это в ans_given список. Каждый ответ отправляется через ajax-запрос в save_ans представление. @ruddra