summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPrabhu Ramachandran2011-11-08 15:40:08 +0530
committerPrabhu Ramachandran2011-11-08 15:40:08 +0530
commit4694d217dd7d5659afdad7ba5937adb85c15371c (patch)
tree2dd78e791414abb6dbd6cf597892942dee0fce8f
parentbed96635b1b0aac8548b6df85e96ee256e5e5bcb (diff)
downloadonline_test-4694d217dd7d5659afdad7ba5937adb85c15371c.tar.gz
online_test-4694d217dd7d5659afdad7ba5937adb85c15371c.tar.bz2
online_test-4694d217dd7d5659afdad7ba5937adb85c15371c.zip
ENH: Command to load questions from XML file.
Added manage command to load questions from XML file. Updated README and including a simple set of sample questions for testing.
-rw-r--r--README.txt47
-rw-r--r--exam/management/__init__.py0
-rw-r--r--exam/management/commands/__init__.py0
-rw-r--r--exam/management/commands/load_questions.py64
-rw-r--r--sample_questions.xml37
5 files changed, 127 insertions, 21 deletions
diff --git a/README.txt b/README.txt
index b1cfb16..fdfddf5 100644
--- a/README.txt
+++ b/README.txt
@@ -4,12 +4,31 @@ Installation
To install/deploy this app follow the steps below:
1. Clone this repository.
+
2. cd to the cloned repo.
- 3. Run $ python manage.py syncdb
- [ enter password etc.]
- 4. Run $ python manage.py runserver <desired_ip>:<desired_port>
- 5. Go to http://server_ip:server_port/admin
- 6. Login with your credentials and add questions to the database.
+
+ 3. Run::
+
+ $ python manage.py syncdb
+ [ enter password etc.]
+
+ 4. Add questions by editing the sample_questions.xml or any other xml
+ file in the same format and then run the following::
+
+ $ python manage.py load_questions sample_questions.xml
+
+ Note that you can supply multiple xml files as arguments and all of
+ those will be added to the database.
+
+ 5. Now, run::
+
+ $ python manage.py runserver <desired_ip>:<desired_port>
+
+ 6. Go to http://server_ip:server_port/admin
+
+ 7. Login with your credentials and look at the questions and modify if
+ needed.
+
7. Now ask users to login at:
http://server_ip:server_port/exam
@@ -19,20 +38,6 @@ To install/deploy this app follow the steps below:
WARNING: django is running in debug mode for this currently, CHANGE it
during deployment
-A sample question
-==================
-
-Here is an example of a good question and tests for it. On the admin
-interface after you login, add a new question with the following fields:
-
- Summary: Fibonnaci
-
- Question: Write function called "fib" which takes a single integer
- argument (say "n") and returns a list of the first "n" fibonacci
- numbers. For example fib(3) -> [1, 1, 2].
-
- Points: 1
+The file sample_questions.xml is a template that you can use for your
+own questions.
- Test:
- assert fib(3) == [1, 1, 2]
- assert fib(6) == [1, 1, 2, 3, 5, 8]
diff --git a/exam/management/__init__.py b/exam/management/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exam/management/__init__.py
diff --git a/exam/management/commands/__init__.py b/exam/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/exam/management/commands/__init__.py
diff --git a/exam/management/commands/load_questions.py b/exam/management/commands/load_questions.py
new file mode 100644
index 0000000..336ed92
--- /dev/null
+++ b/exam/management/commands/load_questions.py
@@ -0,0 +1,64 @@
+# System library imports.
+from os.path import basename
+from xml.dom.minidom import parse
+from htmlentitydefs import name2codepoint
+import re
+
+# Django imports.
+from django.core.management.base import BaseCommand
+
+# Local imports.
+from exam.models import Question
+
+def decode_html(html_str):
+ """Un-escape or decode HTML strings to more usable Python strings.
+ From here: http://wiki.python.org/moin/EscapingHtml
+ """
+ return re.sub('&(%s);' % '|'.join(name2codepoint),
+ lambda m: unichr(name2codepoint[m.group(1)]), html_str)
+
+def clear_questions():
+ """Delete all questions from the database."""
+ for question in Question.objects.all():
+ question.delete()
+
+def load_questions(filename):
+ """Load questions from the given XML file."""
+ q_bank = parse(filename).getElementsByTagName("question")
+
+ for question in q_bank:
+
+ summary_node = question.getElementsByTagName("summary")[0]
+ summary = (summary_node.childNodes[0].data).strip()
+
+ desc_node = question.getElementsByTagName("description")[0]
+ description = (desc_node.childNodes[0].data).strip()
+
+ points_node = question.getElementsByTagName("points")[0]
+ points = int((points_node.childNodes[0].data).strip()) \
+ if points_node else 1
+
+ test_node = question.getElementsByTagName("test")[0]
+ test = decode_html((test_node.childNodes[0].data).strip())
+
+ new_question = Question(summary=summary,
+ description=description,
+ points=points,
+ test=test)
+ new_question.save()
+
+class Command(BaseCommand):
+ args = '<q_file1.xml q_file2.xml>'
+ help = 'loads the questions from given XML files'
+
+ def handle(self, *args, **options):
+ """Handle the command."""
+ # Delete existing stuff.
+ clear_questions()
+
+ # Load from files.
+ for fname in args:
+ self.stdout.write('Importing from {0} ... '.format(basename(fname)))
+ load_questions(fname)
+ self.stdout.write('Done\n')
+
diff --git a/sample_questions.xml b/sample_questions.xml
new file mode 100644
index 0000000..104ea32
--- /dev/null
+++ b/sample_questions.xml
@@ -0,0 +1,37 @@
+<question_bank>
+
+<question>
+<summary>
+Factorial
+</summary>
+<description>
+Write a function called "fact" which takes a single integer argument (say "n")
+and returns the factorial of the number.
+For example fact(3) -> 6
+</description>
+<points>2</points>
+<test>
+assert fact(0) == 1
+assert fact(5) == 120
+</test>
+</question>
+
+<question>
+<summary>
+Simple function
+</summary>
+<description>
+Create a simple function called "sqr" which takes a single argument and
+returns the square of the argument
+For example sqr(3) -> 9.
+</description>
+<points>1</points>
+<test>
+import math
+assert sqr(3) == 9
+assert abs(sqr(math.sqrt(2)) - 2.0) &lt; 1e-14
+</test>
+</question>
+
+
+</question_bank>