Идентификаторы объектов Django, переданные в шаблон, не совпадают внутри функции представления

Когда я отправляю форму, идентификаторы вопросов, которые находятся внутри функции просмотра, не совпадают с идентификаторами вопросов из request.POST.

При отправке функции from операторы печати из функции просмотра выглядят следующим образом:

<QueryDict: {'csrfmiddlewaretoken': ['token here'], 'question_15': ['option1'], 'question_17': ['option1']}>

вопрос_4 вопрос_5

Внутри request.POST идентификаторы 15 и 17, а внутри view 4, 5. Каждый раз, когда я отправляю форму, идентификаторы не совпадают.

Вид:

@login_required
def quiz_view(request):
    questions = QuizQuestion.objects.order_by('?')[:2]

    user = request.user

    if request.method == 'POST':
        print(request.POST)
        for question in questions:
            input_name = f"question_{question.id}"
            print(input_name)
            option_selected = request.POST.get(input_name)
            if option_selected:
                # Check if the user has already responded to this question
                existing_response = QuizUserResponse.objects.filter(user=user, question=question).first()
                if existing_response:
                    # Update existing response
                    existing_response.response_text = getattr(question, option_selected)
                    existing_response.save()
                else:
                    # Create new response
                    QuizUserResponse.objects.create(user=user, question=question, response_text=getattr(question, option_selected))
        return redirect('users:gaming_quiz')
    else:
        context = {
            "questions": questions,
        }
        return render(request, 'general/quiz_template.html', context)

HTML:

<form method="post">
    {% csrf_token %}
    {% for question in questions %}
    <div>
        <label class="question">{{ question.question_text }}</label>
        <ul class="errors">
            {% for error in form.errors %}
                <li>{{ error }}</li>
            {% endfor %}
        </ul>
        <div>
            <label class="form-check-inline">
                <input type="radio" name="question_{{ question.id }}" value="option1"> {{ question.option1 }}
            </label>
            <label class="form-check-inline">
                <input type="radio" name="question_{{ question.id }}" value="option2"> {{ question.option2 }}
            </label>
            <label class="form-check-inline">
                <input type="radio" name="question_{{ question.id }}" value="option3"> {{ question.option3 }}
            </label>
            <label class="form-check-inline">
                <input type="radio" name="question_{{ question.id }}" value="option4"> {{ question.option4 }}
            </label>
        </div>
    </div>
    {% endfor %}
    <button type="submit">Submit</button>
</form>

Как не странно, вы снова обращаетесь к представлению, где снова запрашиваете два случайных QuizQuestion из базы данных, но нет никакой гарантии, что они будут такими же, как при запросе GET, на самом деле очень маловероятно, что это произойдет.

Таким образом, в случае POST-запроса вы должны получить те QuizQuestion, для которых в request.POST указан идентификатор, и наоборот:

@login_required
def quiz_view(request):
    user = request.user
    if request.method == 'POST':
        question_ids = [
            key[9:] for key in request.POST if key.startswith('question_')
        ]
        questions = QuizQuestion.objects.filter(pk__in=question_ids)
        for question in questions:
            input_name = f"question_{question.id}"
            print(input_name)
            option_selected = request.POST.get(input_name)
            if option_selected:
                existing_response = QuizUserResponse.objects.filter(
                    user=user, question=question
                ).first()
                if existing_response:
                    # Update existing response
                    existing_response.response_text = getattr(
                        question, option_selected
                    )
                    existing_response.save()
                else:
                    # Create new response
                    QuizUserResponse.objects.create(
                        user=user,
                        question=question,
                        response_text=getattr(question, option_selected),
                    )
        return redirect('users:gaming_quiz')
    else:
        questions = QuizQuestion.objects.order_by('?')[:2]
    context = {
        'questions': questions,
    }
    return render(request, 'general/quiz_template.html', context)

Note: Allowing getattr(…) [python-doc] to work with an arbitrary (user specified) value for the attribute is often (very) unsafe: it allows the user to obtain sensitive data you want to hide. You might want to check how you can limit the options to improve security.

Вернуться на верх