From: Tom Walker Date: Mon, 21 Jul 2014 21:12:40 +0000 (+0100) Subject: added a new view which lists all completed exams, to allow an admin to view results X-Git-Url: https://git.parisson.com/?a=commitdiff_plain;h=9eadd34cd7580c2f2e8654971375776fae70dc47;p=django_quiz.git added a new view which lists all completed exams, to allow an admin to view results --- diff --git a/README.md b/README.md index 6d3e525..34e9d3a 100644 --- a/README.md +++ b/README.md @@ -23,8 +23,11 @@ Features of each quiz: * Questions can be given a category * Success rate for each category can be monitored on a progress page * Explanation for each question result can be given +* Pass marks can be set * Multiple choice question type * True/False question type +* Custom message displayed for those that pass or fail a quiz + ![Result page](http://i.imgur.com/UJtRZxo.png "Result picture hosted by Imgur") diff --git a/quiz/models.py b/quiz/models.py index 79f4b5f..c0b6913 100644 --- a/quiz/models.py +++ b/quiz/models.py @@ -386,11 +386,13 @@ class Sitting(models.Model): self.incorrect_questions += str(question.id) + "," self.save() + @property def get_incorrect_questions(self): """ - Returns a list of non empty strings + Returns a list of non empty integers, representing the pk of + questions """ - return filter(None, self.incorrect_questions.split(',')) + return [int(q) for q in self.incorrect_questions.split(',') if q] @property def check_if_passed(self): diff --git a/quiz/templates/quiz/sitting_detail.html b/quiz/templates/quiz/sitting_detail.html new file mode 100644 index 0000000..65e8fc7 --- /dev/null +++ b/quiz/templates/quiz/sitting_detail.html @@ -0,0 +1,42 @@ +{% extends 'base.html' %} +{% block title %} +Result of {{ sitting.quiz.title }} for {{ sitting.user }} +{% endblock %} + +{% block content %} +

Quiz title: {{ sitting.quiz.title }}

+

Category: {{ sitting.quiz.category }}

+

{{ sitting.quiz.description }}

+
+

User: {{ sitting.user }}

+

Score: {{ sitting.get_percent_correct }}%

+ + + + + + + + + + + +{% for question in questions %} + + + + + + +{% endfor %} + + + +
Question
{{ question.content }} + {% if question.id in incorrect %} +

incorrect

+ {% else %} +

correct

+ {% endif %} +
+{% endblock %} diff --git a/quiz/templates/quiz/sitting_list.html b/quiz/templates/quiz/sitting_list.html new file mode 100644 index 0000000..8c01436 --- /dev/null +++ b/quiz/templates/quiz/sitting_list.html @@ -0,0 +1,41 @@ +{% extends 'base.html' %} +{% block title %}All Quizzes{% endblock %} + +{% block content %} +

List of complete exams

+ {% if sitting_list %} + + + + + + + + + + + + + + + {% for sitting in sitting_list %} + + + + + + + + {% endfor %} + + + +
UserQuizScore (%)
{{ sitting.user }}{{ sitting.quiz }}{{ sitting.get_current_score }} + + View details + +
+ {% else %} +

There are no complete quizzes.

+ {% endif %} +{% endblock %} diff --git a/quiz/templatetags/quiz_tags.py b/quiz/templatetags/quiz_tags.py index e0715c4..5f70026 100644 --- a/quiz/templatetags/quiz_tags.py +++ b/quiz/templatetags/quiz_tags.py @@ -10,8 +10,8 @@ def correct_answer_for_all(context, question): if the answer is incorrect, informs the user """ answers = question.get_answers() - incorrect_list = context.get('incorrect_questions', '') - if str(question.id) in incorrect_list: + incorrect_list = context.get('incorrect_questions', []) + if question.id in incorrect_list: user_was_incorrect = True else: user_was_incorrect = False diff --git a/quiz/tests.py b/quiz/tests.py index a9a0d3f..1ddb2fa 100644 --- a/quiz/tests.py +++ b/quiz/tests.py @@ -226,19 +226,19 @@ class TestSitting(TestCase): self.assertEqual(self.sitting.result_message, 'Well done') def test_incorrect_and_complete(self): - self.assertEqual(self.sitting.get_incorrect_questions(), []) + self.assertEqual(self.sitting.get_incorrect_questions, []) self.sitting.add_incorrect_question(self.question1) - self.assertIn('1', self.sitting.get_incorrect_questions()) + self.assertIn(1, self.sitting.get_incorrect_questions) question3 = TF_Question.objects.create(id=3, content='oink') self.sitting.add_incorrect_question(question3) - self.assertIn('3', self.sitting.get_incorrect_questions()) + self.assertIn(3, self.sitting.get_incorrect_questions) f_test = self.sitting.add_incorrect_question(self.quiz1) self.assertEqual(f_test, False) - self.assertNotIn('test', self.sitting.get_incorrect_questions()) + self.assertNotIn('test', self.sitting.get_incorrect_questions) self.assertEqual(self.sitting.complete, False) self.sitting.mark_quiz_complete() @@ -334,6 +334,36 @@ class TestNonQuestionViews(TestCase): score, possible = anon_session_score(request.session) self.assertEqual((score, possible), (0.5, 2)) + def test_paper_marking_view(self): + student = User.objects.create_user(username='luke', + email='luke@rebels.com', + password='top_secret') + teacher = User.objects.create_user(username='yoda', + email='yoda@jedis.com', + password='use_d@_force') + question1 = MCQuestion.objects.create(id=1, content='squawk') + question1.quiz.add(self.quiz1) + sitting1 = Sitting.objects.new_sitting(student, self.quiz1) + sitting2 = Sitting.objects.new_sitting(student, self.quiz2) + sitting1.complete = True + sitting1.incorrect_questions = '1' + sitting1.save() + sitting2.complete = True + sitting2.save() + + response = self.client.get('/q/marking/') + self.assertRedirects(response, 'accounts/login/?next=/q/marking/', + status_code=302, target_status_code=404 or 200) + + self.client.login(username='yoda', password='use_d@_force') + response = self.client.get('/q/marking/') + self.assertContains(response, 'test quiz 1') + + response = self.client.get('/q/marking/1/') + self.assertContains(response, 'test quiz 1') + self.assertContains(response, 'squawk') + self.assertContains(response, 'incorrect') + class TestQuestionViewsAnon(TestCase): @@ -678,7 +708,7 @@ class TestTemplateTags(TestCase): '{% correct_answer_for_all question %}') context = Context({'question': self.question1, - 'incorrect_questions': '1,'}) + 'incorrect_questions': [1]}) self.assertTemplateUsed('correct_answer.html') self.assertIn('bing', template.render(context)) diff --git a/quiz/urls.py b/quiz/urls.py index ba15579..db884ff 100644 --- a/quiz/urls.py +++ b/quiz/urls.py @@ -1,7 +1,8 @@ from django.conf.urls import patterns, url from .views import QuizListView, CategoriesListView,\ - ViewQuizListByCategory, QuizUserProgressView, QuizDetailView, QuizTake + ViewQuizListByCategory, QuizUserProgressView, QuizMarkingList,\ + QuizMarkingDetail, QuizDetailView, QuizTake urlpatterns = patterns('', @@ -22,6 +23,14 @@ urlpatterns = patterns('', view=QuizUserProgressView.as_view(), name='quiz_progress'), + url(regex=r'^marking/$', + view=QuizMarkingList.as_view(), + name='quiz_marking'), + + url(regex=r'^marking/(?P[\d.]+)/$', + view=QuizMarkingDetail.as_view(), + name='quiz_marking_detail'), + # passes variable 'quiz_name' to quiz_take view url(regex=r'^(?P[\w-]+)/$', view=QuizDetailView.as_view(), diff --git a/quiz/views.py b/quiz/views.py index ad04ed3..619862c 100644 --- a/quiz/views.py +++ b/quiz/views.py @@ -63,6 +63,33 @@ class QuizUserProgressView(TemplateView): return context +class QuizMarkingList(ListView): + model = Sitting + + @method_decorator(login_required) + def dispatch(self, request, *args, **kwargs): + return super(QuizMarkingList, self).dispatch(request, *args, **kwargs) + + def get_queryset(self): + queryset = super(QuizMarkingList, self).get_queryset() + return queryset.filter(complete=True) + + +class QuizMarkingDetail(DetailView): + model = Sitting + + @method_decorator(login_required) + def dispatch(self, request, *args, **kwargs): + return super(QuizMarkingDetail, self)\ + .dispatch(request, *args, **kwargs) + + def get_context_data(self, **kwargs): + context = super(QuizMarkingDetail, self).get_context_data(**kwargs) + context['questions'] = context['object'].quiz.question_set.all() + context['incorrect'] = context['object'].get_incorrect_questions + return context + + class QuizTake(FormView): form_class = QuestionForm template_name = 'question.html' @@ -164,7 +191,7 @@ def form_valid_user(self, form): def final_result_user(request, sitting, quiz, previous): score = sitting.get_current_score - incorrect = sitting.get_incorrect_questions() + incorrect = sitting.get_incorrect_questions max_score = quiz.get_max_score percent = sitting.get_percent_correct