From c0a1ff463c7f6f7ee67829fba7b33a3cb0ca229e Mon Sep 17 00:00:00 2001 From: Charles Connell Date: Mon, 24 Feb 2014 17:15:40 -0500 Subject: [PATCH] Create quizzes based on keywords --- karmaworld/apps/notes/admin.py | 1 + karmaworld/apps/notes/models.py | 2 +- karmaworld/apps/quizzes/admin.py | 2 +- karmaworld/apps/quizzes/create_quiz.py | 100 ++++++++++++++++++ .../management/commands/create_quiz.py | 20 ++++ .../0002_rename_flashcard_fields.py | 17 +++ karmaworld/apps/quizzes/models.py | 6 +- karmaworld/assets/js/quiz.js | 2 +- karmaworld/templates/quizzes/quiz.html | 4 +- karmaworld/urls.py | 2 +- 10 files changed, 147 insertions(+), 9 deletions(-) create mode 100644 karmaworld/apps/quizzes/create_quiz.py create mode 100644 karmaworld/apps/quizzes/management/commands/create_quiz.py create mode 100644 karmaworld/apps/quizzes/migrations/0002_rename_flashcard_fields.py diff --git a/karmaworld/apps/notes/admin.py b/karmaworld/apps/notes/admin.py index 90e17e6..7a4a65a 100644 --- a/karmaworld/apps/notes/admin.py +++ b/karmaworld/apps/notes/admin.py @@ -14,5 +14,6 @@ class NoteAdmin(admin.ModelAdmin): autocomplete_lookup_fields = { 'fk': ('course', 'user'), } + list_display = ('fp_file', 'upstream_link', 'name', 'id') admin.site.register(Note, NoteAdmin) diff --git a/karmaworld/apps/notes/models.py b/karmaworld/apps/notes/models.py index b73e4ce..54e453f 100644 --- a/karmaworld/apps/notes/models.py +++ b/karmaworld/apps/notes/models.py @@ -242,7 +242,7 @@ class Note(Document): ordering = ['-uploaded_at'] def __unicode__(self): - return u"Note at {0} (from {1})".format(self.fp_file, self.upstream_link) + return u"Note at {0} (from {1}) ({2})".format(self.fp_file, self.upstream_link, self.id) def natural_key(self): """ diff --git a/karmaworld/apps/quizzes/admin.py b/karmaworld/apps/quizzes/admin.py index 66481a1..ea1b8b8 100644 --- a/karmaworld/apps/quizzes/admin.py +++ b/karmaworld/apps/quizzes/admin.py @@ -24,7 +24,7 @@ class MultipleChoiceQuestionInlineAdmin(NestedStackedInline): class FlashCardQuestionInlineAdmin(NestedStackedInline): model = FlashCardQuestion - list_display = ('sideA', 'sideB', 'quiz') + list_display = ('keyword_side', 'definition_side', 'quiz') class TrueFalseQuestionInlineAdmin(NestedStackedInline): diff --git a/karmaworld/apps/quizzes/create_quiz.py b/karmaworld/apps/quizzes/create_quiz.py new file mode 100644 index 0000000..4441e6c --- /dev/null +++ b/karmaworld/apps/quizzes/create_quiz.py @@ -0,0 +1,100 @@ +import random +from karmaworld.apps.notes.models import Note +from karmaworld.apps.quizzes.models import MultipleChoiceQuestion, Quiz, TrueFalseQuestion, MultipleChoiceOption, \ + Keyword, FlashCardQuestion + +KEYWORD_MULTIPLE_CHOICE = 1 +DEFINITION_MULTIPLE_CHOICE = 2 +KEYWORD_DEFINITION_TRUE_FALSE = 3 +FLASHCARD_KEYWORD_BLANK = 4 +GENERATED_QUESTION_TYPE = ( + KEYWORD_MULTIPLE_CHOICE, + DEFINITION_MULTIPLE_CHOICE, + KEYWORD_DEFINITION_TRUE_FALSE, + FLASHCARD_KEYWORD_BLANK, +) + +MULTIPLE_CHOICE_CHOICES = 4 + + +def _create_keyword_multiple_choice(keyword, keywords, quiz): + question_object = MultipleChoiceQuestion.objects.create( + question_text=keyword.definition, + quiz=quiz) + + MultipleChoiceOption.objects.create( + text=keyword.word, + correct=True, + question=question_object) + + for other_keyword in random.sample(keywords.exclude(id=keyword.id), MULTIPLE_CHOICE_CHOICES - 1): + MultipleChoiceOption.objects.create( + text=other_keyword.word, + correct=False, + question=question_object) + + +def _create_definition_multiple_choice(keyword, keywords, quiz): + question_object = MultipleChoiceQuestion.objects.create( + question_text=keyword.word, + quiz=quiz) + + MultipleChoiceOption.objects.create( + text=keyword.definition, + correct=True, + question=question_object) + + for other_keyword in random.sample(keywords.exclude(id=keyword.id), MULTIPLE_CHOICE_CHOICES - 1): + MultipleChoiceOption.objects.create( + text=other_keyword.definition, + correct=False, + question=question_object) + + +def _create_keyword_definition_true_false(keyword, keywords, quiz): + true = random.choice((True, False)) + + if true: + definition = keyword.definition + else: + other_keyword = keywords.exclude(id=keyword.id) + definition = other_keyword.definition + + question_text = 'Is the following a correct definition of {w}:
{d}'. \ + format(w=keyword.word, d=definition) + + TrueFalseQuestion.objects.create( + text=question_text, + quiz=quiz, + true=true) + + +def _create_keyword_flashcard_blank(keyword, quiz): + FlashCardQuestion.objects.create( + definition_side=keyword.definition, + keyword_side=keyword.word, + quiz=quiz) + + +def quiz_from_keywords(note_id): + note_object = Note.objects.get(id=note_id) + quiz_object = Quiz.objects.create(note=note_object, name=note_object.name) + keywords = Keyword.objects.filter(note=note_object) + + for keyword in keywords: + if keyword.word and keyword.definition: + question_type = random.choice(GENERATED_QUESTION_TYPE) + + if question_type is KEYWORD_MULTIPLE_CHOICE: + _create_keyword_multiple_choice(keyword, keywords, quiz_object) + + elif question_type is DEFINITION_MULTIPLE_CHOICE: + _create_definition_multiple_choice(keyword, keywords, quiz_object) + + elif question_type is KEYWORD_DEFINITION_TRUE_FALSE: + _create_keyword_definition_true_false(keyword, keywords, quiz_object) + + elif question_type is FLASHCARD_KEYWORD_BLANK: + _create_keyword_flashcard_blank(keyword, quiz_object) + + diff --git a/karmaworld/apps/quizzes/management/commands/create_quiz.py b/karmaworld/apps/quizzes/management/commands/create_quiz.py new file mode 100644 index 0000000..a0a49da --- /dev/null +++ b/karmaworld/apps/quizzes/management/commands/create_quiz.py @@ -0,0 +1,20 @@ +#!/usr/bin/env python +# -*- coding:utf8 -*- +# Copyright (C) 2014 FinalsClub Foundation +from argparse import ArgumentError +from django.core.management import BaseCommand +from karmaworld.apps.quizzes.create_quiz import quiz_from_keywords + + +class Command(BaseCommand): + args = '' + help = """ + Create a quiz out of the keywords and definitions + already on file for the given note. + """ + + def handle(self, *args, **kwargs): + if len(args) != 1: + raise ArgumentError("Incorrect arguments, see usage") + quiz_from_keywords(args[0]) + diff --git a/karmaworld/apps/quizzes/migrations/0002_rename_flashcard_fields.py b/karmaworld/apps/quizzes/migrations/0002_rename_flashcard_fields.py new file mode 100644 index 0000000..854d6ce --- /dev/null +++ b/karmaworld/apps/quizzes/migrations/0002_rename_flashcard_fields.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +from south.utils import datetime_utils as datetime +from south.db import db +from south.v2 import SchemaMigration +from django.db import models + + +class Migration(SchemaMigration): + + def forwards(self, orm): + db.rename_column(u'quizzes_flashcardquestion', 'sideA', 'keyword_side') + db.rename_column(u'quizzes_flashcardquestion', 'sideB', 'definition_side') + + + def backwards(self, orm): + db.rename_column(u'quizzes_flashcardquestion', 'keyword_side', 'sideA') + db.rename_column(u'quizzes_flashcardquestion', 'definition_side', 'sideB') diff --git a/karmaworld/apps/quizzes/models.py b/karmaworld/apps/quizzes/models.py index 6e659dd..cd161b5 100644 --- a/karmaworld/apps/quizzes/models.py +++ b/karmaworld/apps/quizzes/models.py @@ -87,14 +87,14 @@ class MultipleChoiceOption(models.Model): class FlashCardQuestion(BaseQuizQuestion): - sideA = models.CharField(max_length=2048, verbose_name='Side A') - sideB = models.CharField(max_length=2048, verbose_name='Side B') + keyword_side = models.CharField(max_length=2048, verbose_name='Keyword') + definition_side = models.CharField(max_length=2048, verbose_name='Definition') class Meta: verbose_name = 'Flash card question' def __unicode__(self): - return self.sideA + ' / ' + self.sideB + return self.keyword_side + ' / ' + self.definition_side class TrueFalseQuestion(BaseQuizQuestion): diff --git a/karmaworld/assets/js/quiz.js b/karmaworld/assets/js/quiz.js index 5fa8dbd..fb86301 100644 --- a/karmaworld/assets/js/quiz.js +++ b/karmaworld/assets/js/quiz.js @@ -23,7 +23,7 @@ function addForm(event) { var definitionInput = newForm.find('.definition'); definitionInput.attr('id', newIdRoot + 'definition'); definitionInput.attr('name', newNameRoot + 'definition'); - definitionInput.keydown(addForm); + definitionInput.keydown(tabHandler); var objectIdInput = newForm.find('.object-id'); objectIdInput.attr('id', newIdRoot + 'id'); diff --git a/karmaworld/templates/quizzes/quiz.html b/karmaworld/templates/quizzes/quiz.html index ad62241..364c5b5 100644 --- a/karmaworld/templates/quizzes/quiz.html +++ b/karmaworld/templates/quizzes/quiz.html @@ -88,8 +88,8 @@ {% if 'FlashCardQuestion' in item.0 %} {% with question=item.1 %}
-

{{ question.sideA }}

-

{{ question.sideB }}

+

{{ question.keyword_side }}

+

{{ question.definition_side }}

{% endwith %} {% endif %} diff --git a/karmaworld/urls.py b/karmaworld/urls.py index 56f6ed2..0834cd8 100644 --- a/karmaworld/urls.py +++ b/karmaworld/urls.py @@ -114,7 +114,7 @@ urlpatterns = patterns('', NoteView.as_view(), name='note_detail'), # Quizzes - url(r'^note/' + SLUG.format('school_') + '/' + SLUG.format('course_') +'/'+ SLUG.format('') +'/quiz/$', + url(r'^quiz/(?P[\d]+)/$', QuizView.as_view(), name='quiz'), url(r'^note/' + SLUG.format('school_') + '/' + SLUG.format('course_') +'/'+ SLUG.format('') +'/keywords/$', KeywordEditView.as_view(), name='keyword_edit'), -- 2.25.1