[Answered ]-Django quiz- multiple question- database falsely saves correct answers, Pytest fails at 302

1👍

Likely the main problem is the ans_count, that will, unless specified, always use 1, and thus use one item. This thus means that even if you send five items, the cleaning will still only retrieve the first one. We can set this for example to five to get the first five items:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    ans_count = self.initial.get('ans_count', 5)  # 🖘 first five

    for i in range(ans_count):
        self.fields[f'answer_{i}'] = forms.CharField(
            max_length=200, required=True
        )
        self.fields[f'is_correct_{i}'] = forms.BooleanField(
            required=False,
            widget=forms.CheckboxInput(attrs={'class': 'checkbox'}),
        )

If the user of course enters more items, these will fail to parse.

You can determine these from the data, with:

def __init__(self, *args, **kwargs):
    super().__init__(*args, **kwargs)
    ans_count = self.initial.get('ans_count', 1)
    if self.data is not None:
        try:
            ans_count = int(self.data.get('ans_count', ans_count))
        except ValueError:
            pass

    for i in range(ans_count):
        self.fields[f'answer_{i}'] = forms.CharField(
            max_length=200, required=True
        )
        self.fields[f'is_correct_{i}'] = forms.BooleanField(
            required=False,
            widget=forms.CheckboxInput(attrs={'class': 'checkbox'}),
        )

that being said, what you are trying to do is for a large part already done by a FormSet [Django-doc] so you might want to look if that provides some support, especially since validating multiple small forms is at least as cumbersome as a single form.

0👍

Now I am trying to add Pytest for this view class AddMultiQuestionView(View): from the question.

conftest.py

import pytest
from django.contrib.auth.models import User

@pytest.fixture
def staff_user(db):
    user = User.objects.create_user(username='staffuser', password='staffpassword', is_staff=True)
    return user

@pytest.fixture
def regular_user(db):
    user = User.objects.create_user(username='testuser', password='testpassword')
    return user

test_views.py

import pytest
from django.test import Client
from django.urls import reverse
from ..models import MultiQuesModel, Answer
from django.contrib.auth.models import User
from ..views import AddMultiQuestionView

@pytest.mark.django_db
class TestAddMultiQuestionView:
    def test_view_requires_staff_login(self, client):
        url = reverse("multiform")
        response = client.get(url)
        assert response.status_code == 302  # Awaiting (Redirect)

    def test_view_displays_form_for_staff_user(self, client, staff_user):
        client.login(username='staffuser', password='staffpassword')
        url = reverse("multiform")
        response = client.get(url)
        assert response.status_code == 200
        assert "Number of Answers Anzahl der Antworten" in str(response.content)

    def test_add_multi_question(self, client, staff_user):
        client.login(username='staffuser', password='staffpassword')
        url = reverse("multiform")
        data = {
            "question": "Test question",
            "language_name": 2,  # Database
            "ans_count": 3,
            "answer_0": "Option 1",
            "is_correct_0": True,
            "answer_1": "Option 2",
            "is_correct_1": False,
            "answer_2": "Option 3",
            "is_correct_2": True,
        }
        print("Sending POST request to the view...")
        response = client.post(url, data)
        print("Received response from the view:", response)
        print(response.content)         # Added code- print out
        assert response.status_code == 302  # Awaiting (Redirect)
        assert MultiQuesModel.objects.count() == 1
        assert Answer.objects.count() == 2

Code

plugins: Faker-19.6.1, Flask-Dance-6.2.0, django-4.5.2
collected 3 items                                                                                                                                                                       

tests/test_views.py::TestAddMultiQuestionView::test_view_requires_staff_login PASSED                                                                                             [ 33%]
tests/test_views.py::TestAddMultiQuestionView::test_view_displays_form_for_staff_user PASSED                                                                                     [ 66%]
tests/test_views.py::TestAddMultiQuestionView::test_add_multi_question FAILED                                                                                                    [100%]

====================================================================================== FAILURES =======================================================================================
__________________________________________________________________ TestAddMultiQuestionView.test_add_multi_question ___________________________________________________________________

self = <Learntest.tests.test_views.TestAddMultiQuestionView object at 0x000001BB3960F9D0>, client = <django.test.client.Client object at 0x000001BB39A21950>
staff_user = <User: staffuser>

    def test_add_multi_question(self, client, staff_user):
        client.login(username='staffuser', password='staffpassword')
        url = reverse("multiform")
        data = {
            "question": "Test question",
            "language_name": 2,  # Passen Sie dies entsprechend Ihrer Datenbank an
            "ans_count": 3,
            "answer_0": "Option 1",
            "is_correct_0": True,
            "answer_1": "Option 2",
            "is_correct_1": False,
            "answer_2": "Option 3",
            "is_correct_2": True,
        }
        print("Sending POST request to the view...")
        response = client.post(url, data)
        print("Received response from the view:", response)
        print(response.content)         # Hinzugefügter Code: Printen Sie den Inhalt der Antwort
>       assert response.status_code == 302  # Erwartet eine Weiterleitung (Redirect)
E       assert 200 == 302
E        +  where 200 = <HttpResponse status_code=200, "text/html; charset=utf-8">.status_code

tests\test_views.py:40: AssertionError
-------------------------------------------------------------------------------- Captured stdout call --------------------------------------------------------------------------------- 
Sending POST request to the view...
<QueryDict: {'question': ['Test question'], 'language_name': ['2'], 'ans_count': ['3'], 'answer_0': ['Option 1'], 'is_correct_0': ['True'], 'answer_1': ['Option 2'], 'is_correct_1': ['False'], 'answer_2': ['Option 3'], 'is_correct_2': ['True']}>
3
False
<ul class="errorlist"><li>language_name<ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul></li></ul>
Received response from the view: <HttpResponse status_code=200, "text/html; charset=utf-8">
b'\n<html>\n    <head>\n        <title>\n            Quiz with Django\n        </title>\n        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/boo
tstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">\n    </head>\n    <body>\n        \n\n<style>\n  .greet{\n 
   font-size: 18px;\n    color: #fff;\n    margin-right: 20px;\n  }\n</style>\n\n<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: rgba(34, 97, 21) ;">\n  <butt
on class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">\n    <span class="navbar-toggler-icon"></span>\n  </button>\n  <div class="collapse navbar-collapse" id="navbarNav">\n\n    <ul class="navbar-nav">\n\n          <li class="nav-item active">\n         
   <a class="nav-link" href="/index/">Main page</a>\n          </li>\n\n\n          <li class="nav-item active">\n          \n          </li>\n          <li class="nav-item active">\n 
           <a class="nav-link" href="/multi-form/">Multi question</a>\n          </li>\n\n          <li class="nav-item active">\n            <a class="nav-link" href="/single-form/">S
ingle question</a>\n          </li>\n          \n\n\n          <li class="nav-item">\n            <a class="nav-link" href="/accounts/login/">Login</a>\n          </li>\n\n          <l
i class="nav-item active">\n              <a class="nav-link" href="/register/">Register</a>\n          </li>\n\n          <li class="nav-item active">\n          \n          </li>\n  
        <li class="nav-item active">\n            <a class="nav-link" href="/question-form/">Text question</a>\n          </li>\n          \n\n          <li class="nav-item active">\n 
             <a class="nav-link" href="/multi-site/">Multi Quiz</a>\n          </li>\n\n          <li class="nav-item active">\n              <a class="nav-link" href="/notes/">Corpora
te Notes</a>\n          </li>\n\n          <li class="nav-item active">\n            \n          </li>\n              <a class="nav-link" href="/questionmanager/">Questionmanager</a>\n
          </li>\n          \n\n\n    </ul>\n  </div>\n\n  <span class="greet">Hello, staffuser</span>\n  <span ><a  class="greet" href="/logout/">Logout</a></span>\n  <span ><a  class=
"greet" href="/my-account/">My account</a></span>\n\n</nav>\n\n        \n\n    <div class="jumbotron container row">\n    <div class="col-md-6">\n        <h1>Add Question</h1>\n       
 <div class="card card-body">\n            <form action="" method="POST">\n                <input type="hidden" name="csrfmiddlewaretoken" value="lyBZOx7VgflkeI2SjzoFEgzHhlmMmM6V8JLCGg
M6YZt4Lrp7YOdR7DT4zA5FC84T">\n                <label for="id_question">Question:</label> <input type="text" name="question" value="Test question" maxlength="200" required id="id_questi
on">\n                <br>\n                <label for="id_question">Question:</label> <select name="language_name" required id="id_language_name">\n  <option value="">---------</optio
n>\n\n</select>\n                <label for="id_ans_count">Number of Answers Anzahl der Antworten:</label>\n                <input type="number" name="ans_count" value="3" min="1" required id="id_ans_count">\n                <br>\n                <div id="answers-container">\n                    \n                        \n                    \n                     
   \n                    \n                        \n                    \n                        \n                            <label for="id_answer_0">Answer 0:</label> <input type="text" name="answer_0" value="Option 1" maxlength="200" required id="id_answer_0">\n                            <br>\n                        \n                    \n                  
      \n                            <label for="id_is_correct_0">Is correct 0:</label> <input type="checkbox" name="is_correct_0" class="checkbox" id="id_is_correct_0" checked>\n      
                      <br>\n                        \n                    \n                        \n                            <label for="id_answer_1">Answer 1:</label> <input type="text" name="answer_1" value="Option 2" maxlength="200" required id="id_answer_1">\n                            <br>\n                        \n                    \n                 
       \n                            <label for="id_is_correct_1">Is correct 1:</label> <input type="checkbox" name="is_correct_1" class="checkbox" id="id_is_correct_1">\n             
               <br>\n                        \n                    \n                        \n                            <label for="id_answer_2">Answer 2:</label> <input type="text" name="answer_2" value="Option 3" maxlength="200" required id="id_answer_2">\n                            <br>\n                        \n                    \n                        
\n                            <label for="id_is_correct_2">Is correct 2:</label> <input type="checkbox" name="is_correct_2" class="checkbox" id="id_is_correct_2" checked>\n            
                <br>\n                        \n                    \n                </div>\n                <input type="submit" name="Submit">\n            </form>\n        </div>\n
    </div>\n</div>\n\n    <script>\n        // JavaScript, um dynamisch Antworten hinzuzuf\xc3\xbcgen\n        const ansCountInput = document.getElementById("id_ans_count");\n        c
..\..\..\.venv\Lib\site-packages\_pytest\config\__init__.py:1373
  C:\Users\cairn\Documents\Kodowanie\.venv\Lib\site-packages\_pytest\config\__init__.py:1373: PytestConfigWarning: Unknown config option: python_paths

    self._warn_or_fail_if_strict(f"Unknown config option: {key}\n")

-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
=============================================================================== short test summary info =============================================================================== 
FAILED tests/test_views.py::TestAddMultiQuestionView::test_add_multi_question - assert 200 == 302
======================================================================= 1 failed, 2 passed, 1 warning in 4.16s

if I test it manually it works, it gets written in the database and I get redirected:

[10/Oct/2023 22:38:25] "GET /multi-form/ HTTP/1.1" 200 7701
<QueryDict: {'csrfmiddlewaretoken': ['imjj4MI6Y4IRjX4nzVCGhfadPnwLXPRfoCMfDuiZxdV6QS24BG6VzmrQ0domC0x0'], 'question': ['Pytest?'], 'language_name': ['4'], 'ans_count': ['5'], 'answer_0': ['Snake'], 'is_correct_0': ['on'], 'answer_1': ['Cow'], 'answer_2': ['Human'], 'answer_3': ['Kangaroo'], 'answer_4': ['Dacia'], 'is_correct_4': ['on'], 'Submit': ['Senden']}>       
5
True

<QueryDict: {'question': ['Test question'], 'language_name': ['2'], 'ans_count': ['3'], 'answer_0': ['Option 1'], 'is_correct_0': ['True'], 'answer_1': ['Option 2'], 'is_correct_1': ['False'], 'answer_2': ['Option 3'], 'is_correct_2': ['True']}>
3
False
<ul class="errorlist"><li>language_name<ul class="errorlist"><li>Select a valid choice. That choice is not one of the available choices.</li></ul></li></ul>
b'\n<html>\n    <head>\n        <title>\n            Quiz with Django\n        </title>\n        <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/boo
tstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">\n    </head>\n    <body>\n        \n\n<style>\n  .greet{\n 
   font-size: 18px;\n    color: #fff;\n    margin-right: 20px;\n  }\n</style>\n\n<nav class="navbar navbar-expand-lg navbar-dark" style="background-color: rgba(34, 97, 21) ;">\n  <butt
on class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">\n    <span class="navbar-toggler-icon"></span>\n  </button>\n  <div class="collapse navbar-collapse" id="navbarNav">\n\n    <ul class="navbar-nav">\n\n          <li class="nav-item active">\n         
   <a class="nav-link" href="/index/">Main page</a>\n          </li>\n\n\n          <li class="nav-item active">\n          \n          </li>\n          <li class="nav-item active">\n 
           <a class="nav-link" href="/multi-form/">Multi question</a>\n          </li>\n\n          <li class="nav-item active">\n            <a class="nav-link" href="/single-form/">S
ingle question</a>\n          </li>\n          \n\n\n          <li class="nav-item">\n            <a class="nav-link" href="/accounts/login/">Login</a>\n          </li>\n\n          <l
i class="nav-item active">\n              <a class="nav-link" href="/register/">Register</a>\n          </li>\n\n          <li class="nav-item active">\n          \n          </li>\n  
        <li class="nav-item active">\n            <a class="nav-link" href="/question-form/">Text question</a>\n          </li>\n          \n\n          <li class="nav-item active">\n 
             <a class="nav-link" href="/multi-site/">Multi Quiz</a>\n          </li>\n\n          <li class="nav-item active">\n              <a class="nav-link" href="/notes/">Corpora
te Notes</a>\n          </li>\n\n          <li class="nav-item active">\n            \n          </li>\n              <a class="nav-link" href="/questionmanager/">Questionmanager</a>\n
          </li>\n          \n\n\n    </ul>\n  </div>\n\n  <span class="greet">Hello, staffuser</span>\n  <span ><a  class="greet" href="/logout/">Logout</a></span>\n  <span ><a  class=
"greet" href="/my-account/">My account</a></span>\n\n</nav>\n\n        \n\n    <div class="jumbotron container row">\n    <div class="col-md-6">\n        <h1>Add Question</h1>\n       
 <div class="card card-body">\n            <form action="" method="POST">\n                <input type="hidden" name="csrfmiddlewaretoken" value="HpTXXXBcTZTNGJR51VtvjmOHr8wywRT0RRX3o9
RLCV8k5o9p8yJknJ8Lx8s5BMR8">\n                <label for="id_question">Question:</label> <input type="text" name="question" value="Test question" maxlength="200" required id="id_questi
on">\n                <br>\n                <label for="id_question">Question:</label> <select name="language_name" required id="id_language_name">\n  <option value="">---------</optio
n>\n\n</select>\n                <label for="id_ans_count">Number of Answers Anzahl der Antworten:</label>\n                <input type="number" name="ans_count" value="3" min="1" required id="id_ans_count">\n                <br>\n                <div id="answers-container">\n                    \n                        \n                    \n                     
   \n                    \n                        \n                    \n                        \n                            <label for="id_answer_0">Answer 0:</label> <input type="text" name="answer_0" value="Option 1" maxlength="200" required id="id_answer_0">\n                            <br>\n                        \n                    \n                  
      \n                            <label for="id_is_correct_0">Is correct 0:</label> <input type="checkbox" name="is_correct_0" class="checkbox" id="id_is_correct_0" checked>\n      
                      <br>\n                        \n                    \n                        \n                            <label for="id_answer_1">Answer 1:</label> <input type="text" name="answer_1" value="Option 2" maxlength="200" required id="id_answer_1">\n                            <br>\n                        \n                    \n                 
       \n                            <label for="id_is_correct_1">Is correct 1:</label> <input type="checkbox" name="is_correct_1" class="checkbox" id="id_is_correct_1">\n             
               <br>\n                        \n                    \n                        \n                            <label for="id_answer_2">Answer 2:</label> <input type="text" name="answer_2" value="Option 3" maxlength="200" required id="id_answer_2">\n                            <br>\n                        \n                    \n                        
\n                            <label for="id_is_correct_2">Is correct 2:</label> <input type="checkbox" name="is_correct_2" class="checkbox" id="id_is_correct_2" checked>\n            
                <br>\n                        \n                    \n                </div>\n                <input type="submit" name="Submit">\n            </form>\n        </div>\n
    </div>\n</div>\n\n    <script>\n        // JavaScript, um dynamisch Antworten hinzuzuf\xc3\xbcgen\n        const ansCountInput = document.getElementById("id_ans_count");\n        c
onst answersContainer = document.getElementById("answers-container");\n\n        ansCountInput.addEventListener("change", function () {\n            const ansCount = parseInt(this.valu
wer_${i}" name="answer_${i}" maxlength="200" required>\n                    <label for="id_is_correct_${i}">Is Correct:</label>\n                    <input type="checkbox" id="id_is_correct_${i}" name="is_correct_${i}">\n                    <br>\n                `;\n                answersContainer.appendChild(answerField);\n            }\n        });\n    </script>\n\n    <!-- Uhranzeige mit JavaScript -->\n    <div class="clock" id="clock"></div>\n\n    <script>\n        // JavaScript, um die Uhrzeit anzuzeigen\n        function updateClock() {\n            const clockElement = document.getElementById("clock");\n            const now = new Date();\n            const hours = now.getHours().toString().padStart(2, "0");\n            const minutes = now.getMinutes().toString().padStart(2, "0");\n            const seconds = now.getSeconds().toString().padStart(2, "0");\n            const date = now.toDateStrin[10/Oct/2023 22:38:57] "POST /multi-form/ HTTP/1.1" 302 0
[10/Oct/2023 22:38:57] "GET /success-page/ HTTP/1.1" 200 1419
[10/Oct/2023 22:38:59] "GET /questionmanager/ HTTP/1.1" 200 2818


[{'text': 'Snake', 'is_correct': True}, {'text': 'Cow', 'is_correct': False}, {'text': 'Human', 'is_correct': False}, {'text': 'Kangaroo', 'is_correct': False}, {'text': 'Dacia', 'is_correct': True}]
Preparing to redirect...
[10/Oct/2023 22:38:57] "POST /multi-form/ HTTP/1.1" 302 0
[10/Oct/2023 22:38:57] "GET /success-page/ HTTP/1.1" 200 1419
[10/Oct/2023 22:38:59] "GET /questionmanager/ HTTP/1.1" 200 2818

Leave a comment