Pamela Fox
commited on
Commit
·
1dbd98a
1
Parent(s):
013c0dc
Admin changes
Browse files- quizzes/admin.py +12 -4
- quizzes/migrations/0002_remove_question_answer_status_and_more.py +32 -0
- quizzes/models.py +15 -11
- quizzes/templates/quizzes/display.html +32 -0
- quizzes/templates/quizzes/index.html +19 -0
- quizzes/urls.py +3 -1
- quizzes/views.py +14 -3
quizzes/admin.py
CHANGED
|
@@ -1,7 +1,15 @@
|
|
| 1 |
from django.contrib import admin
|
| 2 |
-
from .models import Quiz, Question, FreeTextAnswer, MultipleChoiceAnswer
|
| 3 |
|
| 4 |
admin.site.register(Quiz)
|
| 5 |
-
|
| 6 |
-
admin.
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
from django.contrib import admin
|
| 2 |
+
from .models import Quiz, Question, Answer, FreeTextAnswer, MultipleChoiceAnswer
|
| 3 |
|
| 4 |
admin.site.register(Quiz)
|
| 5 |
+
|
| 6 |
+
class FreeTextAnswerInline(admin.StackedInline):
|
| 7 |
+
model = FreeTextAnswer
|
| 8 |
+
|
| 9 |
+
class MultipleChoiceAnswerInline(admin.StackedInline):
|
| 10 |
+
model = MultipleChoiceAnswer
|
| 11 |
+
|
| 12 |
+
class QuestionAdmin(admin.ModelAdmin):
|
| 13 |
+
inlines = [FreeTextAnswerInline, MultipleChoiceAnswerInline]
|
| 14 |
+
|
| 15 |
+
admin.site.register(Question, QuestionAdmin)
|
quizzes/migrations/0002_remove_question_answer_status_and_more.py
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Generated by Django 4.1.1 on 2022-09-15 00:57
|
| 2 |
+
|
| 3 |
+
from django.db import migrations, models
|
| 4 |
+
import django.db.models.deletion
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class Migration(migrations.Migration):
|
| 8 |
+
|
| 9 |
+
dependencies = [
|
| 10 |
+
("quizzes", "0001_initial"),
|
| 11 |
+
]
|
| 12 |
+
|
| 13 |
+
operations = [
|
| 14 |
+
migrations.RemoveField(
|
| 15 |
+
model_name="question",
|
| 16 |
+
name="answer_status",
|
| 17 |
+
),
|
| 18 |
+
migrations.AlterField(
|
| 19 |
+
model_name="freetextanswer",
|
| 20 |
+
name="question",
|
| 21 |
+
field=models.OneToOneField(
|
| 22 |
+
on_delete=django.db.models.deletion.CASCADE, to="quizzes.question"
|
| 23 |
+
),
|
| 24 |
+
),
|
| 25 |
+
migrations.AlterField(
|
| 26 |
+
model_name="multiplechoiceanswer",
|
| 27 |
+
name="question",
|
| 28 |
+
field=models.OneToOneField(
|
| 29 |
+
on_delete=django.db.models.deletion.CASCADE, to="quizzes.question"
|
| 30 |
+
),
|
| 31 |
+
),
|
| 32 |
+
]
|
quizzes/models.py
CHANGED
|
@@ -28,10 +28,9 @@ class Quiz(models.Model):
|
|
| 28 |
class Question(models.Model):
|
| 29 |
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
|
| 30 |
prompt = models.CharField(max_length=200)
|
| 31 |
-
answer_status = models.CharField(default='unanswered', max_length=16)
|
| 32 |
|
| 33 |
def __str__(self):
|
| 34 |
-
return
|
| 35 |
|
| 36 |
def display(self):
|
| 37 |
print(self.prompt)
|
|
@@ -44,15 +43,22 @@ class Question(models.Model):
|
|
| 44 |
print(f"Sorry, it was: {self.answer.correct_answer}")
|
| 45 |
self.answer_status = 'incorrect'
|
| 46 |
|
| 47 |
-
|
| 48 |
-
|
| 49 |
-
|
| 50 |
-
|
|
|
|
| 51 |
correct_answer = models.CharField(max_length=200)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 52 |
case_sensitive = models.BooleanField(default=False)
|
| 53 |
|
| 54 |
def __str__(self):
|
| 55 |
-
return
|
| 56 |
|
| 57 |
def is_correct(self, user_answer):
|
| 58 |
if not self.case_sensitive:
|
|
@@ -65,13 +71,11 @@ class FreeTextAnswer(models.Model):
|
|
| 65 |
else:
|
| 66 |
print("Type your answer in (don't worry about capitalization):")
|
| 67 |
|
| 68 |
-
class MultipleChoiceAnswer(
|
| 69 |
-
question = models.ForeignKey(Question, on_delete=models.CASCADE)
|
| 70 |
-
correct_answer = models.CharField(max_length=200)
|
| 71 |
choices = fields.ArrayField(models.CharField(max_length=200, blank=True))
|
| 72 |
|
| 73 |
def __str__(self):
|
| 74 |
-
return f"
|
| 75 |
|
| 76 |
def is_correct(self, user_answer):
|
| 77 |
"""Assumes user answer is number corresponding to answer."""
|
|
|
|
| 28 |
class Question(models.Model):
|
| 29 |
quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
|
| 30 |
prompt = models.CharField(max_length=200)
|
|
|
|
| 31 |
|
| 32 |
def __str__(self):
|
| 33 |
+
return self.prompt
|
| 34 |
|
| 35 |
def display(self):
|
| 36 |
print(self.prompt)
|
|
|
|
| 43 |
print(f"Sorry, it was: {self.answer.correct_answer}")
|
| 44 |
self.answer_status = 'incorrect'
|
| 45 |
|
| 46 |
+
class Answer(models.Model):
|
| 47 |
+
question = models.OneToOneField(
|
| 48 |
+
Question,
|
| 49 |
+
on_delete=models.CASCADE
|
| 50 |
+
)
|
| 51 |
correct_answer = models.CharField(max_length=200)
|
| 52 |
+
|
| 53 |
+
|
| 54 |
+
class Meta:
|
| 55 |
+
abstract = True
|
| 56 |
+
|
| 57 |
+
class FreeTextAnswer(Answer):
|
| 58 |
case_sensitive = models.BooleanField(default=False)
|
| 59 |
|
| 60 |
def __str__(self):
|
| 61 |
+
return self.correct_answer
|
| 62 |
|
| 63 |
def is_correct(self, user_answer):
|
| 64 |
if not self.case_sensitive:
|
|
|
|
| 71 |
else:
|
| 72 |
print("Type your answer in (don't worry about capitalization):")
|
| 73 |
|
| 74 |
+
class MultipleChoiceAnswer(Answer):
|
|
|
|
|
|
|
| 75 |
choices = fields.ArrayField(models.CharField(max_length=200, blank=True))
|
| 76 |
|
| 77 |
def __str__(self):
|
| 78 |
+
return f"{self.correct_answer} from {self.choices}"
|
| 79 |
|
| 80 |
def is_correct(self, user_answer):
|
| 81 |
"""Assumes user answer is number corresponding to answer."""
|
quizzes/templates/quizzes/display.html
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE HTML>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width">
|
| 6 |
+
<title>Quiz {{ quiz.id }}</title>
|
| 7 |
+
</head>
|
| 8 |
+
<body>
|
| 9 |
+
<h1>{{ quiz.name }}</h1>
|
| 10 |
+
|
| 11 |
+
<form action="{% url 'quizzes:grade' question.id %}" method="post">
|
| 12 |
+
{% csrf_token %}
|
| 13 |
+
{% for question in quiz.question_set.all %}
|
| 14 |
+
<section>
|
| 15 |
+
<h3>{{ question.prompt }}</h3>
|
| 16 |
+
{% if question.freetextanswer %}
|
| 17 |
+
<input type="text" name="{{ question.pk }}">
|
| 18 |
+
{% else %}
|
| 19 |
+
{% for choice in question.multiplechoiceanswer.choices %}
|
| 20 |
+
<label>
|
| 21 |
+
<input type="radio" name="{{ question.pk }}" value="{{ choice }}">
|
| 22 |
+
{{ choice}}
|
| 23 |
+
</label>
|
| 24 |
+
{% endfor %}
|
| 25 |
+
{% endif %}
|
| 26 |
+
</section>
|
| 27 |
+
{% endfor %}
|
| 28 |
+
|
| 29 |
+
<button type="submit">Check answers</button>
|
| 30 |
+
</form>
|
| 31 |
+
</body>
|
| 32 |
+
</html>
|
quizzes/templates/quizzes/index.html
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE HTML>
|
| 2 |
+
<html>
|
| 3 |
+
<head>
|
| 4 |
+
<meta charset="utf-8">
|
| 5 |
+
<meta name="viewport" content="width=device-width">
|
| 6 |
+
<title>Quizzes</title>
|
| 7 |
+
</head>
|
| 8 |
+
<body>
|
| 9 |
+
{% if quiz_list %}
|
| 10 |
+
<ul>
|
| 11 |
+
{% for quiz in quiz_list %}
|
| 12 |
+
<li><a href="{% url 'quizzes:display' quiz.id %}">{{ quiz.name }}</a></li>
|
| 13 |
+
{% endfor %}
|
| 14 |
+
</ul>
|
| 15 |
+
{% else %}
|
| 16 |
+
<p>No quizzes are available.</p>
|
| 17 |
+
{% endif %}
|
| 18 |
+
</body>
|
| 19 |
+
</html>
|
quizzes/urls.py
CHANGED
|
@@ -2,9 +2,11 @@ from django.urls import path
|
|
| 2 |
|
| 3 |
from . import views
|
| 4 |
|
|
|
|
|
|
|
| 5 |
urlpatterns = [
|
| 6 |
path('', views.index, name='index'),
|
| 7 |
-
# ex: /polls/5/
|
| 8 |
path('<int:quiz_id>/', views.display, name='display'),
|
|
|
|
| 9 |
|
| 10 |
]
|
|
|
|
| 2 |
|
| 3 |
from . import views
|
| 4 |
|
| 5 |
+
app_name = 'quizzes'
|
| 6 |
+
|
| 7 |
urlpatterns = [
|
| 8 |
path('', views.index, name='index'),
|
|
|
|
| 9 |
path('<int:quiz_id>/', views.display, name='display'),
|
| 10 |
+
path('<int:quiz_id>/grade/', views.grade, name='grade'),
|
| 11 |
|
| 12 |
]
|
quizzes/views.py
CHANGED
|
@@ -1,7 +1,18 @@
|
|
| 1 |
-
from django.
|
|
|
|
|
|
|
| 2 |
|
| 3 |
def index(request):
|
| 4 |
-
|
|
|
|
|
|
|
|
|
|
| 5 |
|
| 6 |
def display(request, quiz_id):
|
| 7 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from django.shortcuts import get_object_or_404,render
|
| 2 |
+
|
| 3 |
+
from .models import Quiz
|
| 4 |
|
| 5 |
def index(request):
|
| 6 |
+
quiz_list = Quiz.objects.all()
|
| 7 |
+
context = {'quiz_list': quiz_list}
|
| 8 |
+
return render(request, 'quizzes/index.html', context)
|
| 9 |
+
|
| 10 |
|
| 11 |
def display(request, quiz_id):
|
| 12 |
+
quiz = get_object_or_404(Quiz, pk=quiz_id)
|
| 13 |
+
return render(request, 'quizzes/display.html', {'quiz': quiz})
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
def grade(request, quiz_id):
|
| 17 |
+
quiz = get_object_or_404(Quiz, pk=quiz_id)
|
| 18 |
+
return render(request, 'quizzes/display.html', {'quiz': quiz})
|