summaryrefslogtreecommitdiff
path: root/yaksh/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'yaksh/models.py')
-rw-r--r--yaksh/models.py355
1 files changed, 289 insertions, 66 deletions
diff --git a/yaksh/models.py b/yaksh/models.py
index e3212fd..949b87e 100644
--- a/yaksh/models.py
+++ b/yaksh/models.py
@@ -6,7 +6,8 @@ import ruamel.yaml
from ruamel.yaml.scalarstring import PreservedScalarString
from ruamel.yaml.comments import CommentedMap
from random import sample
-from collections import Counter
+from collections import Counter, defaultdict
+
from django.db import models
from django.contrib.auth.models import User, Group, Permission
from django.contrib.contenttypes.models import ContentType
@@ -45,6 +46,7 @@ languages = (
("cpp", "C++ Language"),
("java", "Java Language"),
("scilab", "Scilab"),
+ ("r", "R"),
)
question_types = (
@@ -80,6 +82,17 @@ string_check_type = (
("exact", "Case Sensitive"),
)
+legend_display_types = {
+ "mcq": {"label": "Objective Type"},
+ "mcc": {"label": "Objective Type"},
+ "code": {"label": "Programming"},
+ "upload": {"label": "Upload"},
+ "integer": {"label": "Objective Type"},
+ "string": {"label": "Objective Type"},
+ "float": {"label": "Objective Type"},
+ "arrange": {"label": "Objective Type"},
+ }
+
attempts = [(i, i) for i in range(1, 6)]
attempts.append((-1, 'Infinite'))
@@ -94,8 +107,10 @@ MOD_GROUP_NAME = 'moderator'
def get_assignment_dir(instance, filename):
- upload_dir = instance.question_paper.quiz.description.replace(" ", "_")
- return os.sep.join((upload_dir, instance.user.username,
+ folder_name = instance.course.name.replace(" ", "_")
+ sub_folder_name = instance.question_paper.quiz.description.replace(
+ " ", "_")
+ return os.sep.join((folder_name, sub_folder_name, instance.user.username,
str(instance.assignmentQuestion.id),
filename
))
@@ -208,7 +223,7 @@ def write_templates_to_zip(zipfile, template_path, data, filename, filepath):
str(rendered_template))
-def render_template(template_path, data):
+def render_template(template_path, data=None):
with open(template_path) as f:
template_data = f.read()
template = Template(template_data)
@@ -243,7 +258,7 @@ class Lesson(models.Model):
html_data = models.TextField(null=True, blank=True)
# Creator of the lesson
- creator = models.ForeignKey(User)
+ creator = models.ForeignKey(User, on_delete=models.CASCADE)
# Activate/Deactivate Lesson
active = models.BooleanField(default=True)
@@ -284,7 +299,7 @@ class Lesson(models.Model):
if os.path.exists(file_path):
os.remove(file_path)
- def _add_lesson_to_zip(self, module, course, zip_file, path):
+ def _add_lesson_to_zip(self, next_unit, module, course, zip_file, path):
lesson_name = self.name.replace(" ", "_")
course_name = course.name.replace(" ", "_")
module_name = module.name.replace(" ", "_")
@@ -302,17 +317,20 @@ class Lesson(models.Model):
lesson_file.file.name)))
zip_file.writestr(filename, lesson_file.file.read())
unit_file_path = os.sep.join((
- path, "templates", "yaksh", "unit.html"
+ path, "templates", "yaksh", "download_course_templates",
+ "unit.html"
))
lesson_data = {"course": course, "module": module,
- "lesson": self, "lesson_files": lesson_files}
+ "lesson": self, "next_unit": next_unit,
+ "lesson_files": lesson_files}
write_templates_to_zip(zip_file, unit_file_path, lesson_data,
lesson_name, sub_folder_name)
#############################################################################
class LessonFile(models.Model):
- lesson = models.ForeignKey(Lesson, related_name="lesson")
+ lesson = models.ForeignKey(Lesson, related_name="lesson",
+ on_delete=models.CASCADE)
file = models.FileField(upload_to=get_file_dir, default=None)
def remove(self):
@@ -460,7 +478,7 @@ class Quiz(models.Model):
is_exercise = models.BooleanField(default=False)
- creator = models.ForeignKey(User, null=True)
+ creator = models.ForeignKey(User, null=True, on_delete=models.CASCADE)
objects = QuizManager()
@@ -517,7 +535,7 @@ class Quiz(models.Model):
except QuestionPaper.DoesNotExist:
qp = None
ans_ppr = AnswerPaper.objects.filter(
- user=user, course=course, question_paper=qp
+ user_id=user.id, course_id=course.id, question_paper_id=qp
).order_by("-attempt_number")
if ans_ppr.exists():
status = ans_ppr.first().status
@@ -525,6 +543,18 @@ class Quiz(models.Model):
status = "not attempted"
return status
+ def get_answerpaper_passing_status(self, user, course):
+ try:
+ qp = self.questionpaper_set.get().id
+ except QuestionPaper.DoesNotExist:
+ qp = None
+ ans_ppr = AnswerPaper.objects.filter(
+ user_id=user.id, course_id=course.id, question_paper_id=qp
+ ).order_by("-attempt_number")
+ if ans_ppr.exists():
+ return any([paper.passed for paper in ans_ppr])
+ return False
+
def _create_quiz_copy(self, user):
question_papers = self.questionpaper_set.all()
new_quiz = self
@@ -541,16 +571,43 @@ class Quiz(models.Model):
return '%s: on %s for %d minutes' % (desc, self.start_date_time,
self.duration)
+ def _add_quiz_to_zip(self, next_unit, module, course, zip_file, path):
+ quiz_name = self.description.replace(" ", "_")
+ course_name = course.name.replace(" ", "_")
+ module_name = module.name.replace(" ", "_")
+ sub_folder_name = os.sep.join((
+ course_name, module_name, quiz_name
+ ))
+ unit_file_path = os.sep.join((
+ path, "templates", "yaksh", "download_course_templates",
+ "quiz.html"
+ ))
+ quiz_data = {"course": course, "module": module,
+ "quiz": self, "next_unit": next_unit}
+
+ write_templates_to_zip(zip_file, unit_file_path, quiz_data,
+ quiz_name, sub_folder_name)
+
##########################################################################
class LearningUnit(models.Model):
""" Maintain order of lesson and quiz added in the course """
order = models.IntegerField()
type = models.CharField(max_length=16)
- lesson = models.ForeignKey(Lesson, null=True, blank=True)
- quiz = models.ForeignKey(Quiz, null=True, blank=True)
+ lesson = models.ForeignKey(Lesson, null=True, blank=True,
+ on_delete=models.CASCADE)
+ quiz = models.ForeignKey(Quiz, null=True, blank=True,
+ on_delete=models.CASCADE)
check_prerequisite = models.BooleanField(default=True)
+ def get_lesson_or_quiz(self):
+ unit = None
+ if self.type == 'lesson':
+ unit = self.lesson
+ else:
+ unit = self.quiz
+ return unit
+
def toggle_check_prerequisite(self):
if self.check_prerequisite:
self.check_prerequisite = False
@@ -558,10 +615,12 @@ class LearningUnit(models.Model):
self.check_prerequisite = True
def get_completion_status(self, user, course):
- course_status = CourseStatus.objects.filter(user=user, course=course)
+ course_status = CourseStatus.objects.filter(
+ user_id=user.id, course_id=course.id
+ )
state = "not attempted"
if course_status.exists():
- if self in course_status.first().completed_units.all():
+ if course_status.first().completed_units.filter(id=self.id):
state = "completed"
elif self.type == "quiz":
state = self.quiz.get_answerpaper_status(user, course)
@@ -572,7 +631,7 @@ class LearningUnit(models.Model):
def has_prerequisite(self):
return self.check_prerequisite
- def is_prerequisite_passed(self, user, learning_module, course):
+ def is_prerequisite_complete(self, user, learning_module, course):
ordered_units = learning_module.learning_unit.order_by("order")
ordered_units_ids = list(ordered_units.values_list("id", flat=True))
current_unit_index = ordered_units_ids.index(self.id)
@@ -599,6 +658,14 @@ class LearningUnit(models.Model):
order=self.order, type="lesson", lesson=new_lesson)
return new_unit
+ def __str__(self):
+ name = None
+ if self.type == 'lesson':
+ name = self.lesson.name
+ else:
+ name = self.quiz.description
+ return name
+
###############################################################################
class LearningModule(models.Model):
@@ -608,8 +675,10 @@ class LearningModule(models.Model):
name = models.CharField(max_length=255)
description = models.TextField(default=None, null=True, blank=True)
order = models.IntegerField(default=0)
- creator = models.ForeignKey(User, related_name="module_creator")
+ creator = models.ForeignKey(User, related_name="module_creator",
+ on_delete=models.CASCADE)
check_prerequisite = models.BooleanField(default=True)
+ check_prerequisite_passes = models.BooleanField(default=False)
html_data = models.TextField(null=True, blank=True)
active = models.BooleanField(default=True)
is_trial = models.BooleanField(default=False)
@@ -639,6 +708,9 @@ class LearningModule(models.Model):
def toggle_check_prerequisite(self):
self.check_prerequisite = not self.check_prerequisite
+ def toggle_check_prerequisite_passes(self):
+ self.check_prerequisite_passes = not self.check_prerequisite_passes
+
def get_next_unit(self, current_unit_id):
ordered_units = self.learning_unit.order_by("order")
ordered_units_ids = list(ordered_units.values_list("id", flat=True))
@@ -666,7 +738,7 @@ class LearningModule(models.Model):
default_status = "inprogress"
return default_status
- def is_prerequisite_passed(self, user, course):
+ def is_prerequisite_complete(self, user, course):
""" Check if prerequisite module is completed """
ordered_modules = course.learning_module.order_by("order")
ordered_modules_ids = list(ordered_modules.values_list(
@@ -684,6 +756,35 @@ class LearningModule(models.Model):
success = False
return success
+ def get_passing_status(self, user, course):
+ course_status = CourseStatus.objects.filter(user=user, course=course)
+ if course_status.exists():
+ learning_units_with_quiz = self.learning_unit.filter(type='quiz')
+ ordered_units = learning_units_with_quiz.order_by("order")
+
+ statuses = [
+ unit.quiz.get_answerpaper_passing_status(user, course)
+ for unit in ordered_units
+ ]
+
+ if not statuses:
+ status = False
+ else:
+ status = all(statuses)
+ return status
+
+ def is_prerequisite_passed(self, user, course):
+ """ Check if prerequisite module is passed """
+ ordered_modules = course.learning_module.order_by("order")
+ if ordered_modules.first() == self:
+ return True
+ else:
+ if self.order == 0:
+ return True
+ prev_module = ordered_modules.get(order=self.order-1)
+ status = prev_module.get_passing_status(user, course)
+ return status
+
def has_prerequisite(self):
return self.check_prerequisite
@@ -715,12 +816,28 @@ class LearningModule(models.Model):
course_name = course.name.replace(" ", "_")
folder_name = os.sep.join((course_name, module_name))
lessons = self.get_lesson_units()
- for lesson in lessons:
- lesson._add_lesson_to_zip(self, course, zip_file, path)
+
+ units = self.get_learning_units()
+ for idx, unit in enumerate(units):
+ next_unit = units[(idx + 1) % len(units)]
+ if unit.type == 'lesson':
+ unit.lesson._add_lesson_to_zip(next_unit,
+ self,
+ course,
+ zip_file,
+ path)
+ else:
+ unit.quiz._add_quiz_to_zip(next_unit,
+ self,
+ course,
+ zip_file,
+ path)
+
module_file_path = os.sep.join((
- path, "templates", "yaksh", "module.html"
+ path, "templates", "yaksh", "download_course_templates",
+ "module.html"
))
- module_data = {"course": course, "module": self, "lessons": lessons}
+ module_data = {"course": course, "module": self, "units": units}
write_templates_to_zip(zip_file, module_file_path, module_data,
module_name, folder_name)
@@ -736,7 +853,8 @@ class Course(models.Model):
active = models.BooleanField(default=True)
code = models.CharField(max_length=128, null=True, blank=True)
hidden = models.BooleanField(default=False)
- creator = models.ForeignKey(User, related_name='creator')
+ creator = models.ForeignKey(User, related_name='creator',
+ on_delete=models.CASCADE)
students = models.ManyToManyField(User, related_name='students')
requests = models.ManyToManyField(User, related_name='requests')
rejected = models.ManyToManyField(User, related_name='rejected')
@@ -744,6 +862,7 @@ class Course(models.Model):
teachers = models.ManyToManyField(User, related_name='teachers')
is_trial = models.BooleanField(default=False)
instructions = models.TextField(default=None, null=True, blank=True)
+ view_grade = models.BooleanField(default=False)
learning_module = models.ManyToManyField(LearningModule,
related_name='learning_module')
@@ -764,7 +883,8 @@ class Course(models.Model):
null=True
)
- grading_system = models.ForeignKey(GradingSystem, null=True, blank=True)
+ grading_system = models.ForeignKey(GradingSystem, null=True, blank=True,
+ on_delete=models.CASCADE)
objects = CourseManager()
@@ -784,6 +904,7 @@ class Course(models.Model):
copy_module_name = "Copy of {0}".format(module.name)
new_module = module._create_module_copy(user, copy_module_name)
new_course.learning_module.add(new_module)
+ return new_course
def request(self, *users):
self.requests.add(*users)
@@ -855,16 +976,28 @@ class Course(models.Model):
demo_que_ppr = QuestionPaper()
demo_que_ppr.create_demo_quiz_ppr(demo_quiz, user)
success = True
+ file_path = os.sep.join(
+ (os.path.dirname(__file__), "templates", "yaksh",
+ "demo_video.html")
+ )
+ rendered_text = render_template(file_path)
+ lesson_data = "Demo Lesson\n{0}".format(rendered_text)
demo_lesson = Lesson.objects.create(
- name="Demo lesson", description="demo lesson",
- html_data="demo lesson", creator=user)
+ name="Demo Lesson", description=lesson_data,
+ html_data=lesson_data, creator=user
+ )
quiz_unit = LearningUnit.objects.create(
- order=1, type="quiz", quiz=demo_quiz)
+ order=1, type="quiz", quiz=demo_quiz, check_prerequisite=False
+ )
lesson_unit = LearningUnit.objects.create(
- order=2, type="lesson", lesson=demo_lesson)
+ order=2, type="lesson", lesson=demo_lesson,
+ check_prerequisite=False
+ )
learning_module = LearningModule.objects.create(
- name="demo module", description="demo module", creator=user,
- html_data="demo module")
+ name="Demo Module", description="<center>Demo Module</center>",
+ creator=user, html_data="<center>Demo Module</center>",
+ check_prerequisite=False
+ )
learning_module.learning_unit.add(quiz_unit)
learning_module.learning_unit.add(lesson_unit)
course.learning_module.add(learning_module)
@@ -972,7 +1105,12 @@ class Course(models.Model):
with zipfile.ZipFile(zip_file_name, "a") as zip_file:
course_name = self.name.replace(" ", "_")
modules = self.get_learning_modules()
- file_path = os.sep.join((path, "templates", "yaksh", "index.html"))
+ file_path = os.sep.join(
+ (
+ path, "templates", "yaksh",
+ "download_course_templates", "index.html"
+ )
+ )
write_static_files_to_zip(zip_file, course_name, path,
static_files)
course_data = {"course": self, "modules": modules}
@@ -1000,9 +1138,10 @@ class CourseStatus(models.Model):
completed_units = models.ManyToManyField(LearningUnit,
related_name="completed_units")
current_unit = models.ForeignKey(LearningUnit, related_name="current_unit",
- null=True, blank=True)
- course = models.ForeignKey(Course)
- user = models.ForeignKey(User)
+ null=True, blank=True,
+ on_delete=models.CASCADE)
+ course = models.ForeignKey(Course, on_delete=models.CASCADE)
+ user = models.ForeignKey(User, on_delete=models.CASCADE)
grade = models.CharField(max_length=255, null=True, blank=True)
percentage = models.FloatField(default=0.0)
percent_completed = models.IntegerField(default=0)
@@ -1014,7 +1153,7 @@ class CourseStatus(models.Model):
if self.is_course_complete():
self.calculate_percentage()
if self.course.grading_system is None:
- grading_system = GradingSystem.objects.get(name='default')
+ grading_system = GradingSystem.objects.get(name__contains='default')
else:
grading_system = self.course.grading_system
grade = grading_system.get_grade(self.percentage)
@@ -1048,17 +1187,22 @@ class CourseStatus(models.Model):
self.current_unit = unit
self.save()
+ def __str__(self):
+ return "{0} status for {1}".format(
+ self.course.name, self.user.username
+ )
+
###############################################################################
class ConcurrentUser(models.Model):
- concurrent_user = models.OneToOneField(User)
+ concurrent_user = models.OneToOneField(User, on_delete=models.CASCADE)
session_key = models.CharField(max_length=40)
###############################################################################
class Profile(models.Model):
"""Profile for a user to store roll number and other details."""
- user = models.OneToOneField(User)
+ user = models.OneToOneField(User, on_delete=models.CASCADE)
roll_number = models.CharField(max_length=20)
institute = models.CharField(max_length=128)
department = models.CharField(max_length=64)
@@ -1076,18 +1220,23 @@ class Profile(models.Model):
def get_user_dir(self):
"""Return the output directory for the user."""
- user_dir = join(settings.OUTPUT_DIR, str(self.user.username))
+ user_dir = join(settings.OUTPUT_DIR, str(self.user.id))
if not exists(user_dir):
os.makedirs(user_dir)
os.chmod(user_dir, stat.S_IRWXU | stat.S_IRWXG | stat.S_IRWXO)
return user_dir
+ def get_moderated_courses(self):
+ return Course.objects.filter(teachers=self.user)
+
def _toggle_moderator_group(self, group_name):
group = Group.objects.get(name=group_name)
if self.is_moderator:
self.user.groups.add(group)
else:
self.user.groups.remove(group)
+ for course in self.get_moderated_courses():
+ course.remove_teachers(self.user)
def save(self, *args, **kwargs):
if self.pk is not None:
@@ -1131,7 +1280,8 @@ class Question(models.Model):
snippet = models.TextField(blank=True)
# user for particular question
- user = models.ForeignKey(User, related_name="user")
+ user = models.ForeignKey(User, related_name="user",
+ on_delete=models.CASCADE)
# Does this question allow partial grading
partial_grading = models.BooleanField(default=False)
@@ -1144,6 +1294,42 @@ class Question(models.Model):
# Solution for the question.
solution = models.TextField(blank=True)
+ tc_code_types = {
+ "python": [
+ ("standardtestcase", "Standard TestCase"),
+ ("stdiobasedtestcase", "StdIO TestCase"),
+ ("hooktestcase", "Hook TestCase")
+ ],
+ "c": [
+ ("standardtestcase", "Standard TestCase"),
+ ("stdiobasedtestcase", "StdIO TestCase"),
+ ("hooktestcase", "Hook TestCase")
+ ],
+ "cpp": [
+ ("standardtestcase", "Standard TestCase"),
+ ("stdiobasedtestcase", "StdIO TestCase"),
+ ("hooktestcase", "Hook TestCase")
+ ],
+ "java": [
+ ("standardtestcase", "Standard TestCase"),
+ ("stdiobasedtestcase", "StdIO TestCase"),
+ ("hooktestcase", "Hook TestCase")
+ ],
+ "r": [
+ ("standardtestcase", "Standard TestCase"),
+ ("hooktestcase", "Hook TestCase")
+ ],
+ "bash": [
+ ("standardtestcase", "Standard TestCase"),
+ ("stdiobasedtestcase", "StdIO TestCase"),
+ ("hooktestcase", "Hook TestCase")
+ ],
+ "scilab": [
+ ("standardtestcase", "Standard TestCase"),
+ ("hooktestcase", "Hook TestCase")
+ ]
+ }
+
def consolidate_answer_data(self, user_answer, user=None):
question_data = {}
metadata = {}
@@ -1345,6 +1531,24 @@ class Question(models.Model):
files, extract_path = extract_files(zip_file_path)
self.read_yaml(extract_path, user, files)
+ def get_test_case_options(self):
+ options = None
+ if self.type == "code":
+ options = self.tc_code_types.get(self.language)
+ elif self.type == "mcq" or self.type == "mcc":
+ options = [("mcqtestcase", "Mcq TestCase")]
+ elif self.type == "integer":
+ options = [("integertestcase", "Integer TestCase")]
+ elif self.type == "float":
+ options = [("floattestcase", "Float TestCase")]
+ elif self.type == "string":
+ options = [("stringtestcase", "String TestCase")]
+ elif self.type == "arrange":
+ options = [("arrangetestcase", "Arrange TestCase")]
+ elif self.type == "upload":
+ options = [("hooktestcase", "Hook TestCase")]
+ return options
+
def __str__(self):
return self.summary
@@ -1352,7 +1556,8 @@ class Question(models.Model):
###############################################################################
class FileUpload(models.Model):
file = models.FileField(upload_to=get_upload_dir, blank=True)
- question = models.ForeignKey(Question, related_name="question")
+ question = models.ForeignKey(Question, related_name="question",
+ on_delete=models.CASCADE)
extract = models.BooleanField(default=False)
hide = models.BooleanField(default=False)
@@ -1377,13 +1582,16 @@ class FileUpload(models.Model):
self.hide = True
self.save()
+ def get_filename(self):
+ return os.path.basename(self.file.name)
+
###############################################################################
class Answer(models.Model):
"""Answers submitted by the users."""
# The question for which user answers.
- question = models.ForeignKey(Question)
+ question = models.ForeignKey(Question, on_delete=models.CASCADE)
# The answer submitted by the user.
answer = models.TextField(null=True, blank=True)
@@ -1408,7 +1616,7 @@ class Answer(models.Model):
self.marks = marks
def __str__(self):
- return self.answer
+ return "Answer for question {0}".format(self.question.summary)
###############################################################################
@@ -1458,7 +1666,7 @@ class QuestionPaper(models.Model):
"""Question paper stores the detail of the questions."""
# Question paper belongs to a particular quiz.
- quiz = models.ForeignKey(Quiz)
+ quiz = models.ForeignKey(Quiz, on_delete=models.CASCADE)
# Questions that will be mandatory in the quiz.
fixed_questions = models.ManyToManyField(Question)
@@ -1570,7 +1778,9 @@ class QuestionPaper(models.Model):
attempts = AnswerPaper.objects.get_total_attempt(questionpaper=self,
user=user,
course_id=course_id)
- return attempts != self.quiz.attempts_allowed
+ attempts_allowed = attempts < self.quiz.attempts_allowed
+ infinite_attempts = self.quiz.attempts_allowed == -1
+ return attempts_allowed or infinite_attempts
def can_attempt_now(self, user, course_id):
if self._is_attempt_allowed(user, course_id):
@@ -1743,10 +1953,10 @@ class AnswerPaperManager(models.Manager):
def _get_answerpapers_for_quiz(self, questionpaper_id, course_id,
status=False):
if not status:
- return self.filter(question_paper_id=questionpaper_id,
+ return self.filter(question_paper_id__in=questionpaper_id,
course_id=course_id)
else:
- return self.filter(question_paper_id=questionpaper_id,
+ return self.filter(question_paper_id__in=questionpaper_id,
course_id=course_id,
status="completed")
@@ -1788,14 +1998,15 @@ class AnswerPaperManager(models.Manager):
.distinct()
def get_user_all_attempts(self, questionpaper, user, course_id):
- return self.filter(question_paper=questionpaper, user=user,
+ return self.filter(question_paper_id__in=questionpaper, user_id=user,
course_id=course_id)\
.order_by('-attempt_number')
def get_user_data(self, user, questionpaper_id, course_id,
attempt_number=None):
if attempt_number is not None:
- papers = self.filter(user=user, question_paper_id=questionpaper_id,
+ papers = self.filter(user_id=user.id,
+ question_paper_id__in=questionpaper_id,
course_id=course_id,
attempt_number=attempt_number)
else:
@@ -1813,7 +2024,8 @@ class AnswerPaperManager(models.Manager):
def get_user_best_of_attempts_marks(self, quiz, user_id, course_id):
best_attempt = 0.0
- papers = self.filter(question_paper__quiz=quiz, course_id=course_id,
+ papers = self.filter(question_paper__quiz_id=quiz.id,
+ course_id=course_id,
user=user_id).values("marks_obtained")
if papers:
best_attempt = max([marks["marks_obtained"] for marks in papers])
@@ -1825,15 +2037,15 @@ class AnswerPaper(models.Model):
"""A answer paper for a student -- one per student typically.
"""
# The user taking this question paper.
- user = models.ForeignKey(User)
+ user = models.ForeignKey(User, on_delete=models.CASCADE)
questions = models.ManyToManyField(Question, related_name='questions')
# The Quiz to which this question paper is attached to.
- question_paper = models.ForeignKey(QuestionPaper)
+ question_paper = models.ForeignKey(QuestionPaper, on_delete=models.CASCADE)
# Answepaper will be unique to the course
- course = models.ForeignKey(Course, null=True)
+ course = models.ForeignKey(Course, null=True, on_delete=models.CASCADE)
# The attempt number for the question paper.
attempt_number = models.IntegerField()
@@ -2073,6 +2285,16 @@ class AnswerPaper(models.Model):
def get_previous_answers(self, question):
return self.answers.filter(question=question).order_by('-id')
+ def get_categorized_question_indices(self):
+ category_question_map = defaultdict(list)
+ for index, question in enumerate(self.get_all_ordered_questions(), 1):
+ question_category = legend_display_types.get(question.type)
+ if question_category:
+ category_question_map[
+ question_category["label"]
+ ].append(index)
+ return dict(category_question_map)
+
def validate_answer(self, user_answer, question, json_data=None, uid=None,
server_port=SERVER_POOL_PORT):
"""
@@ -2223,20 +2445,19 @@ class AnswerPaper(models.Model):
##############################################################################
class AssignmentUploadManager(models.Manager):
- def get_assignments(self, qp, que_id=None, user_id=None):
+ def get_assignments(self, qp, que_id=None, user_id=None, course_id=None):
if que_id and user_id:
assignment_files = AssignmentUpload.objects.filter(
assignmentQuestion_id=que_id, user_id=user_id,
- question_paper=qp
+ question_paper=qp, course_id=course_id
)
file_name = User.objects.get(id=user_id).get_full_name()
else:
assignment_files = AssignmentUpload.objects.filter(
- question_paper=qp
+ question_paper=qp, course_id=course_id
)
-
file_name = "{0}_Assignment_files".format(
- assignment_files[0].question_paper.quiz.description
+ assignment_files[0].course.name
)
return assignment_files, file_name
@@ -2244,16 +2465,20 @@ class AssignmentUploadManager(models.Manager):
##############################################################################
class AssignmentUpload(models.Model):
- user = models.ForeignKey(User)
- assignmentQuestion = models.ForeignKey(Question)
+ user = models.ForeignKey(User, on_delete=models.CASCADE)
+ assignmentQuestion = models.ForeignKey(Question, on_delete=models.CASCADE)
assignmentFile = models.FileField(upload_to=get_assignment_dir)
- question_paper = models.ForeignKey(QuestionPaper, blank=True, null=True)
+ question_paper = models.ForeignKey(QuestionPaper, blank=True, null=True,
+ on_delete=models.CASCADE)
+ course = models.ForeignKey(Course, null=True, blank=True,
+ on_delete=models.CASCADE)
objects = AssignmentUploadManager()
##############################################################################
class TestCase(models.Model):
- question = models.ForeignKey(Question, blank=True, null=True)
+ question = models.ForeignKey(Question, blank=True, null=True,
+ on_delete=models.CASCADE)
type = models.CharField(max_length=24, choices=test_case_types, null=True)
@@ -2390,15 +2615,13 @@ class TestCaseOrder(models.Model):
"""
# Answerpaper of the user.
- answer_paper = models.ForeignKey(AnswerPaper, related_name="answer_paper")
+ answer_paper = models.ForeignKey(AnswerPaper, related_name="answer_paper",
+ on_delete=models.CASCADE)
# Question in an answerpaper.
- question = models.ForeignKey(Question)
+ question = models.ForeignKey(Question, on_delete=models.CASCADE)
# Order of the test case for a question.
order = models.TextField()
- class Meta:
- unique_together = ("answer_paper", "question", "order")
-
##############################################################################