Issue
I am trying to make a question page where a user can click the questions ID. Upon clicking they will be redirected to another page to answer this question with the question text appearing and showing the multiple choice questions. How would I go around doing this?
So far I have this
[![Example][1]][1]
Clicking number one will take the user to the question with the multiple choices for this question and question text
Model
from asyncio import FastChildWatcher
import email
from pyexpat import model
from xxlimited import Null
from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager
class userCouncil(BaseUserManager):
def create_user(self, userID, password=None):
if not email:
raise ValueError("Email is required")
user = self.model(userID = self.normalize_email(userID))
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, userID, password):
user = self.model(userID = self.normalize_email(userID))
user.set_password(password)
user.is_staff = True
user.is_admin = True
user.save(using=self._db)
return user
class sni(models.Model):
SNI = models.CharField(max_length=256, primary_key=True)
Used = models.IntegerField(null=True, blank=True)
password = None
USERNAME_FIELD = 'SNI'
def __str__(self):
return self.SNI
class Account(AbstractBaseUser):
userID = models.EmailField(primary_key= True ,max_length=256, unique=True)
name = models.CharField(max_length=100)
dateOfBirth = models.DateField(max_length=8, null=True)
homeAddress = models.CharField(max_length=100, null=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
sni = models.OneToOneField(sni, on_delete=models.CASCADE, null=True, blank=True)
USERNAME_FIELD = 'userID'
objects = userCouncil()
def __str__(self):
return self.userID
def has_perm(self, perm, obj=None):
return self.is_admin
def has_module_perms(self, app_label):
return True
class Question(models.Model):
QuestionsID = models.AutoField(primary_key=True, unique=True)
QuestionText = models.CharField(max_length=256, null = True)
def __str__(self):
return str(self.QuestionsID)
class Option(models.Model):
OptionID = models.AutoField(primary_key=True, unique=True)
OptionText = models.CharField(max_length=256, null=True)
QuestionsID = models.ForeignKey(Question, on_delete=models.CASCADE)
def __str__(self):
return str(self.OptionID)
class Result(models.Model):
ResponseID = models.AutoField(primary_key=True, unique=True)
userID = models.ForeignKey(Account, on_delete=models.CASCADE)
QuestionsID = models.ForeignKey(Question, on_delete=models.CASCADE)
ChosenOptionID = models.ForeignKey(Option, on_delete=models.CASCADE)
def __str__(self):
return str(self.ResponseID)
View
from telnetlib import LOGOUT
from django.shortcuts import redirect, render
from django.http import HttpResponse
from matplotlib import use
from matplotlib.pyplot import get
from matplotlib.style import context
from werkzeug import Request
from .models import Account, Question, sni
from django.contrib.auth.hashers import make_password, check_password
from django.contrib.auth.forms import UserCreationForm
from django.contrib import messages
from django.contrib.auth import authenticate, logout
from django.contrib.auth import login as dj_login
from django.forms import ModelForm, forms
from django.contrib.auth.decorators import login_required
from .forms import AccountAuthenticationForm, SNIForm, createUserForm
def login(request):
context = {}
if request.method == 'POST':
username = request.POST.get('username').lower()
password = request.POST.get('password')
user = authenticate(request, userID = username, password = password)
form = AccountAuthenticationForm(request.GET)
if user is not None:
dj_login(request, user)
return redirect('dashboardPage')
else:
messages.info(request, "userID or password is incorrect")
return render(request, 'base.html', context)
def registerPage(request):
form = createUserForm()
form2 = SNIForm()
if request.method == 'POST':
form = createUserForm(request.POST)
form2 = SNIForm(request.POST)
if form.is_valid() and form2.is_valid:
snival = form2.data['SNI']
print(snival)
if sni.objects.filter(SNI = snival, Used = 1).exists():
form.save()
userID = form.cleaned_data.get('userID')
messages.success(request, "Account created for: " + userID)
return redirect('loginPage')
context = {'form' : form, 'form2' : form2}
return render(request, 'register.html', context)
@login_required(login_url='loginPage')
def dashboardPage(request):
context = {'Questions': Question.objects.all}
return render(request, 'dashboard.html', context)
def logout_view(request):
logout(request)
messages.success(request, "You were logged out!")
return redirect("loginPage")
dashboard html
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous">
<style>
body,
html {
margin: 0;
padding: 0;
height: 100%;
background: #7abecc !important;
}
.user_card {
width: 350px;
margin-top: auto;
margin-bottom: auto;
background: #74cfbf;
position: relative;
display: flex;
justify-content: center;
flex-direction: column;
padding: 10px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-webkit-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-moz-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 5px;
}
.form_container {
margin-top: 20px;
}
#form-title{
color: #fff;
}
.login_btn {
width: 100%;
background: #33ccff !important;
color: white !important;
}
.login_btn:focus {
box-shadow: none !important;
outline: 0px !important;
}
.login_container {
padding: 0 2rem;
}
.input-group-text {
background: #f7ba5b !important;
color: white !important;
border: 0 !important;
border-radius: 0.25rem 0 0 0.25rem !important;
}
.input_user,
.input_pass:focus {
box-shadow: none !important;
outline: 0px !important;
}
#messages{
background-color: grey;
color: #fff;
padding: 10px;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container h-100">
<div class="d-flex justify-content-center h-100">
<div class="user_card">
<div class="d-flex justify-content-center">
<h3 id="form-title">Questions</h3>
</div>
<div class="d-flex justify-content-center form_container">
<div class="mt-4">
{% for q in Questions %}
<h6>{{ q.QuestionsID }}: {{ q.QuestionText }}</h8>
{% endfor %}
</div>
{% for message in messages %}
<p id='messages'>{{message}} </p>
{% endfor %}
</div>
<div class="mt-4">
<div class="d-flex justify-content-center links">
<a href= "{% url 'logOut' %}" class="ml-2"> LOGOUT </a>
</div>
</html>
EDIT:
When i try to run - I will get the error django.urls.exceptions.NoReverseMatch: Reverse for 'question' with arguments '('',)' not found. 1 pattern(s) tried: ['question/(?P[0-9]+)/$']
I have followed everything however I have made the change to the URL section to 'question'
Here is my URL.py
from django.urls import path
from django.urls.resolvers import URLPattern
from . import views
urlpatterns = [
path('login', views.login, name = 'loginPage'),
path('registerPage', views.registerPage, name = 'registerPage'),
path('', views.dashboardPage, name = 'dashboardPage'),
path('log_out', views.logout_view, name = 'logOut'),
path('question/<int:id>/', views.question_detail, name = 'question'),
]
EDIT 2
views
@login_required(login_url='loginPage')
def question_detail(request, id):
question = Question.objects.get(QuestionsID = id)
options = Option.objects.filter(QuestionsID = question)
current_user = request.user
c = current_user.userID
acc = Account.objects.get(userID=c)
check = Result.objects.filter(QuestionsID = question).exists()
check2 = Result.objects.filter(userID = acc).exists()
if check and check2:
messages.error(request, "Already Answered!")
return redirect('dashboardPage')
if request.method == 'POST':
OptionID = request.POST.get('result')
if OptionID == None:
messages.error(request, "Option Not Selected")
else:
op = Option.objects.get(OptionID = OptionID)
obj = Result.objects.create(userID = acc, QuestionsID = question, ChosenOptionID = op)
obj.save()
messages.success(request, "Answer Submitted")
return redirect('dashboardPage')
context = {'question' : question,
'options' : options}
return render(request, 'questionForm.html', context)
URL
path('question/<int:id>/', views.question_detail, name = 'question'),
HTML - DASHBOARD HTML
<head>
<title>Dashboard</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" integrity="sha384-gfdkjb5BdAXd+lj+gudLWI+BXq4IuLW5IT+brZEZsLFm++aCMlF1V92rMkPaX4PP" crossorigin="anonymous">
<style>
body,
html {
margin: 0;
padding: 0;
height: 100%;
background: #7abecc !important;
}
.user_card {
width: 350px;
margin-top: auto;
margin-bottom: auto;
background: #74cfbf;
position: relative;
display: flex;
justify-content: center;
flex-direction: column;
padding: 10px;
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-webkit-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
-moz-box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
border-radius: 5px;
}
.form_container {
margin-top: 20px;
}
#form-title{
color: #fff;
}
.login_btn {
width: 100%;
background: #33ccff !important;
color: white !important;
}
.login_btn:focus {
box-shadow: none !important;
outline: 0px !important;
}
.login_container {
padding: 0 2rem;
}
.input-group-text {
background: #f7ba5b !important;
color: white !important;
border: 0 !important;
border-radius: 0.25rem 0 0 0.25rem !important;
}
.input_user,
.input_pass:focus {
box-shadow: none !important;
outline: 0px !important;
}
#messages{
background-color: grey;
color: #fff;
padding: 10px;
margin-top: 10px;
}
</style>
</head>
<body>
<div class="container h-100">
<div class="d-flex justify-content-center h-100">
<div class="user_card">
<div class="d-flex justify-content-center">
<h3 id="form-title">Questions</h3>
</div>
<div class="d-flex justify-content-center form_container">
<div class="mt-4">
{% for q in Questions %}
<h6><a href="q.QuestionID">{{ q.QuestionsID }}</a>: {{ q.QuestionText }}</h8>
{% endfor %}
</div>
</div>
{% for message in messages %}
<p id='messages'>{{message}} </p>
{% endfor %}
<div class="mt-4">
<div class="d-flex justify-content-center links">
<a href= "{% url 'logOut' %}" class="ml-2"> LOGOUT </a>
</div>
</html>
For the mean time I have removed the URL part in the html
Solution
I don't want to write your code for you, but I am willing to give you the idea of an approach to solve your problem.
Your question in your comment,
Do i use a request parameter and then set the questionID as a href link?
is basically, YES!
Add an answerPage view, and HTML template that will take a particular question id that you will pass via a url from the dashboard page. Then filter the options that belong to that question:
@login_required(login_url='loginPage')
def dashboardPage(request):
context = {'Questions': Question.objects.all()}
return render(request, 'dashboard.html', context)
@login_required(login_url='loginPage')
def answerPage(request, questions_id):
question = Question.objects.get(QuestionsID = questions_id)
options = Option.objects.filter(QuestionsID = question)
if request.method == 'POST':
# here you can put the code that will get the results and save them
context = {
'question': question,
'options': options
}
return render(request, 'answer.html', context)
Your dashboard page should have urls that will pass the questions id to the answerPage view:
dashboard.html
...
{% for q in Questions %}
<h6><a href="{% url 'answerPage' q.QuestionID %}">{{ q.QuestionsID }}</a>: {{ q.QuestionText }}</h6>
{% endfor %}
...
Your answer.html page can then print out that specific question, and the options that you passed in:
answer.html
...
<div>{{ question }}</div>
{% for option in options %}
<input type="radio" id="{{ option.OptionID }}" name="result" value="{{ option.OptionId }}">
<label for="{{ option.OptionID" }}>{{ option.OptionText }}</label><br>
{% endfor %}
...
The reason for the error you're getting, Reverse for 'question' with arguments '('',)' not found
is that there is that your view is expecting <int:id>
but if you put what I included, it is expecting <int: questions_id>
. The view is currently not getting any parameter, questions_id. You can change the path (easier), or the view so they match:
Either:
path('question/<int:questions_id>/', views.answerPage, name = 'question'),
OR
change the view from answerPage to
def question_detail(request, id):
question = Question.objects.get(QuestionsID = id)
options = Option.objects.filter(QuestionsID = question)
if request.method == 'POST':
# here you can put the code that will get the results and save them
context = {
'question': question,
'options': options
}
return render(request, 'answer.html', context)
And then change the dashboard.html to:
...
{% for q in Questions %}
<h6><a href="{% url 'question_detail' q.QuestionID %}">{{ q.QuestionsID }}</a>: {{ q.QuestionText }}</h6>
{% endfor %}
...
Now it's up to you to take those responses and process them so the results are stored.
Answered By - raphael
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.