generalise a QuestionBase
This commit is contained in:
+2
-9
@@ -16,7 +16,7 @@ from sortedm2m.fields import SortedManyToManyField
|
|||||||
|
|
||||||
import string
|
import string
|
||||||
|
|
||||||
from generic.models import CidUser, CidUserGroup, ExamUserStatus, Examination, ExamBase, QuestionNote, UserAnswerBase, UserUserGroup
|
from generic.models import CidUser, CidUserGroup, ExamUserStatus, Examination, ExamBase, QuestionBase, QuestionNote, UserAnswerBase, UserUserGroup
|
||||||
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from helpers.images import image_as_base64
|
from helpers.images import image_as_base64
|
||||||
@@ -72,7 +72,7 @@ class QuestionType(models.Model):
|
|||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class AnatomyQuestion(models.Model):
|
class AnatomyQuestion(QuestionBase):
|
||||||
question_type = models.ForeignKey(
|
question_type = models.ForeignKey(
|
||||||
QuestionType, on_delete=models.SET_NULL, null=True, default=1
|
QuestionType, on_delete=models.SET_NULL, null=True, default=1
|
||||||
)
|
)
|
||||||
@@ -114,11 +114,6 @@ class AnatomyQuestion(models.Model):
|
|||||||
structure = models.ForeignKey(
|
structure = models.ForeignKey(
|
||||||
Structure, on_delete=models.SET_NULL, null=True, blank=True
|
Structure, on_delete=models.SET_NULL, null=True, blank=True
|
||||||
)
|
)
|
||||||
created_date = models.DateTimeField(default=timezone.now)
|
|
||||||
|
|
||||||
open_access = models.BooleanField(
|
|
||||||
help_text="If a question should be freely available to browse", default=True
|
|
||||||
)
|
|
||||||
|
|
||||||
author = models.ManyToManyField(
|
author = models.ManyToManyField(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
@@ -127,8 +122,6 @@ class AnatomyQuestion(models.Model):
|
|||||||
related_name="anatomy_authored_questions",
|
related_name="anatomy_authored_questions",
|
||||||
)
|
)
|
||||||
|
|
||||||
notes = GenericRelation(QuestionNote)
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
permissions = ()
|
permissions = ()
|
||||||
|
|
||||||
|
|||||||
+21
-1
@@ -24,6 +24,7 @@ from django.contrib.auth.models import User
|
|||||||
from django.db.models.signals import post_save
|
from django.db.models.signals import post_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
|
|
||||||
class Plane(models.Model):
|
class Plane(models.Model):
|
||||||
plane = models.CharField(max_length=200, unique=True)
|
plane = models.CharField(max_length=200, unique=True)
|
||||||
|
|
||||||
@@ -71,15 +72,29 @@ class QuestionBase(models.Model):
|
|||||||
default=False,
|
default=False,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
created_date = models.DateTimeField(default=timezone.now)
|
||||||
|
|
||||||
|
open_access = models.BooleanField(
|
||||||
|
help_text="If a question should be freely available to browse", default=True
|
||||||
|
)
|
||||||
|
|
||||||
|
feedback = models.TextField(null=True, blank=True, help_text="Question Feedback")
|
||||||
|
|
||||||
|
notes = GenericRelation("generic.QuestionNote")
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
abstract = True
|
abstract = True
|
||||||
|
|
||||||
def get_unanswered_mark_and_text(self) -> tuple(int, str):
|
def get_unanswered_mark_and_text(self) -> tuple[ int, str ]:
|
||||||
"""
|
"""
|
||||||
Override in models if needed
|
Override in models if needed
|
||||||
"""
|
"""
|
||||||
return (0, "Not answered")
|
return (0, "Not answered")
|
||||||
|
|
||||||
|
def get_primary_answer(self):
|
||||||
|
"""If this makes sense in the question/answer context override"""
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
class ExamBase(models.Model):
|
class ExamBase(models.Model):
|
||||||
name = models.CharField(max_length=200, help_text="Name of the exam")
|
name = models.CharField(max_length=200, help_text="Name of the exam")
|
||||||
@@ -436,6 +451,11 @@ class UserAnswerBase(models.Model):
|
|||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse(f"{self.app_name}:user_answer_view", kwargs={"pk": self.pk})
|
return reverse(f"{self.app_name}:user_answer_view", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
|
def get_answer(self):
|
||||||
|
"""might need overriding"""
|
||||||
|
return self.answer
|
||||||
|
|
||||||
|
|
||||||
class NoteType(models.Model):
|
class NoteType(models.Model):
|
||||||
note_type = models.CharField(max_length=200)
|
note_type = models.CharField(max_length=200)
|
||||||
|
|
||||||
|
|||||||
+1
-4
@@ -1803,10 +1803,7 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
answer_score = score
|
answer_score = score
|
||||||
ans = text
|
ans = text
|
||||||
else:
|
else:
|
||||||
if exam.app_name == "rapids" and user_answer.normal:
|
ans = user_answer.get_answer()
|
||||||
ans = "Normal"
|
|
||||||
else:
|
|
||||||
ans = user_answer.answer
|
|
||||||
answer_score = user_answer.get_answer_score()
|
answer_score = user_answer.get_answer_score()
|
||||||
|
|
||||||
correct_answer = q.get_primary_answer()
|
correct_answer = q.get_primary_answer()
|
||||||
|
|||||||
+50
-16
@@ -37,6 +37,7 @@ from generic.models import (
|
|||||||
ExamBase,
|
ExamBase,
|
||||||
Plane,
|
Plane,
|
||||||
Contrast,
|
Contrast,
|
||||||
|
QuestionBase,
|
||||||
QuestionNote,
|
QuestionNote,
|
||||||
UserAnswerBase,
|
UserAnswerBase,
|
||||||
UserUserGroup,
|
UserUserGroup,
|
||||||
@@ -79,7 +80,7 @@ def findMiddle(input_list):
|
|||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class Long(models.Model):
|
class Long(QuestionBase):
|
||||||
description = models.TextField(
|
description = models.TextField(
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Description of the case, for admin organisation, will not be visible when taking",
|
help_text="Description of the case, for admin organisation, will not be visible when taking",
|
||||||
@@ -87,8 +88,6 @@ class Long(models.Model):
|
|||||||
|
|
||||||
history = models.TextField(null=True, blank=True)
|
history = models.TextField(null=True, blank=True)
|
||||||
|
|
||||||
feedback = models.TextField(null=True, blank=True)
|
|
||||||
|
|
||||||
# TODO: merge with atlas condition / signs / finding
|
# TODO: merge with atlas condition / signs / finding
|
||||||
# condition = tagulous.models.TagField(
|
# condition = tagulous.models.TagField(
|
||||||
# to=Condition,
|
# to=Condition,
|
||||||
@@ -117,8 +116,6 @@ class Long(models.Model):
|
|||||||
# help_text=
|
# help_text=
|
||||||
# "If we know the source of the image")
|
# "If we know the source of the image")
|
||||||
verified = models.BooleanField(default=False)
|
verified = models.BooleanField(default=False)
|
||||||
created_date = models.DateTimeField(default=timezone.now)
|
|
||||||
published_date = models.DateTimeField(blank=True, null=True)
|
|
||||||
author = models.ManyToManyField(
|
author = models.ManyToManyField(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
blank=True,
|
blank=True,
|
||||||
@@ -130,10 +127,6 @@ class Long(models.Model):
|
|||||||
default=False, help_text="Question has been scrapped and will not be shown"
|
default=False, help_text="Question has been scrapped and will not be shown"
|
||||||
)
|
)
|
||||||
|
|
||||||
open_access = models.BooleanField(
|
|
||||||
help_text="If a question should be freely available to browse", default=True
|
|
||||||
)
|
|
||||||
|
|
||||||
recreate_json = models.BooleanField(
|
recreate_json = models.BooleanField(
|
||||||
help_text="If the json cache needs updating", default=False
|
help_text="If the json cache needs updating", default=False
|
||||||
)
|
)
|
||||||
@@ -146,8 +139,6 @@ class Long(models.Model):
|
|||||||
|
|
||||||
series = SortedManyToManyField("LongSeries", related_name="long")
|
series = SortedManyToManyField("LongSeries", related_name="long")
|
||||||
|
|
||||||
notes = GenericRelation(QuestionNote)
|
|
||||||
|
|
||||||
# question_file = models.FileField(upload_to=question_file_directory_path, blank=True, null=True)
|
# question_file = models.FileField(upload_to=question_file_directory_path, blank=True, null=True)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
@@ -354,6 +345,12 @@ class Long(models.Model):
|
|||||||
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
|
def get_unanswered_mark_and_text(self) -> tuple[int, str]:
|
||||||
|
"""
|
||||||
|
Override in models if needed
|
||||||
|
"""
|
||||||
|
return (4, ("Not answered",) * 5)
|
||||||
|
|
||||||
# def GetNonFeedbackQuestionImages(self):
|
# def GetNonFeedbackQuestionImages(self):
|
||||||
# return self.get_images()
|
# return self.get_images()
|
||||||
|
|
||||||
@@ -431,14 +428,12 @@ class LongSeries(models.Model):
|
|||||||
)
|
)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
#if self.long:
|
# if self.long:
|
||||||
# long_id = ", ".format([long.pk for long in self.long.all()])
|
# long_id = ", ".format([long.pk for long in self.long.all()])
|
||||||
# # long_id = self.long.pk
|
# # long_id = self.long.pk
|
||||||
#else:
|
# else:
|
||||||
# long_id = "None"
|
# long_id = "None"
|
||||||
return "{}/{} : {}".format(
|
return "{}/{} : {}".format(self.pk, self.get_examination(), self.description)
|
||||||
self.pk, self.get_examination(), self.description
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_author_objects(self):
|
def get_author_objects(self):
|
||||||
"""Returns a comma seperated text list of authors"""
|
"""Returns a comma seperated text list of authors"""
|
||||||
@@ -655,6 +650,35 @@ class Exam(ExamBase):
|
|||||||
|
|
||||||
exam_user_status = GenericRelation(ExamUserStatus)
|
exam_user_status = GenericRelation(ExamUserStatus)
|
||||||
|
|
||||||
|
def get_exam_question_json(self, question_id):
|
||||||
|
q = get_object_or_404(Long, pk=question_id)
|
||||||
|
|
||||||
|
# exam_order.append(q.id)
|
||||||
|
|
||||||
|
# Loop through longimage associations
|
||||||
|
images = []
|
||||||
|
image_titles = []
|
||||||
|
for series in q.series.all():
|
||||||
|
# image_array = []
|
||||||
|
# for i in series.images.all():
|
||||||
|
# image_array.append(image_as_base64(i.image))
|
||||||
|
# #image_array.append(i.image.url)
|
||||||
|
image_array = [image_as_base64(i.image) for i in series.images.all()]
|
||||||
|
images.append(image_array)
|
||||||
|
image_titles.append(series.get_examination())
|
||||||
|
|
||||||
|
exam_question = {
|
||||||
|
"title": q.history,
|
||||||
|
"images": images,
|
||||||
|
"image_titles": image_titles,
|
||||||
|
# "feedback_image": [],
|
||||||
|
# "annotations": [str(q.image_annotations)],
|
||||||
|
"type": "long",
|
||||||
|
"images_json": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
return exam_question
|
||||||
|
|
||||||
def get_exam_json(self, based=True):
|
def get_exam_json(self, based=True):
|
||||||
questions = self.exam_questions.all()
|
questions = self.exam_questions.all()
|
||||||
|
|
||||||
@@ -849,6 +873,15 @@ class UserAnswer(UserAnswerBase):
|
|||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_answer(self):
|
||||||
|
(
|
||||||
|
self.answer_observations,
|
||||||
|
self.answer_interpretation,
|
||||||
|
self.answer_principle_diagnosis,
|
||||||
|
self.answer_differential_diagnosis,
|
||||||
|
self.answer_management,
|
||||||
|
)
|
||||||
|
|
||||||
def get_answer_string(self) -> str:
|
def get_answer_string(self) -> str:
|
||||||
return f"""
|
return f"""
|
||||||
Observations:
|
Observations:
|
||||||
@@ -868,6 +901,7 @@ Management:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@reversion.register
|
@reversion.register
|
||||||
class AnswerMarks(models.Model):
|
class AnswerMarks(models.Model):
|
||||||
score = models.CharField(max_length=3, choices=UserAnswer.ScoreOptions.choices)
|
score = models.CharField(max_length=3, choices=UserAnswer.ScoreOptions.choices)
|
||||||
|
|||||||
+91
-91
@@ -978,97 +978,97 @@ def mark(request, exam_id, sk):
|
|||||||
# )
|
# )
|
||||||
|
|
||||||
|
|
||||||
def exam_scores_cid_user(request, pk, cid, passcode):
|
#def exam_scores_cid_user(request, pk, cid, passcode):
|
||||||
exam = get_object_or_404(Exam, pk=pk)
|
# exam = get_object_or_404(Exam, pk=pk)
|
||||||
|
#
|
||||||
# TODO:Need some kind of test for cid
|
# # TODO:Need some kind of test for cid
|
||||||
|
#
|
||||||
if not exam.exam_mode:
|
# if not exam.exam_mode:
|
||||||
raise Http404("Packet not in exam mode")
|
# raise Http404("Packet not in exam mode")
|
||||||
|
#
|
||||||
if not exam.check_cid_user(cid, passcode, request):
|
# if not exam.check_cid_user(cid, passcode, request):
|
||||||
raise Http404("Error accessing exam")
|
# raise Http404("Error accessing exam")
|
||||||
|
#
|
||||||
|
#
|
||||||
questions = exam.exam_questions.all()
|
# questions = exam.exam_questions.all()
|
||||||
|
#
|
||||||
# answers_and_marks = []
|
# # answers_and_marks = []
|
||||||
answers_marks = []
|
# answers_marks = []
|
||||||
# answers = []
|
# # answers = []
|
||||||
answer_text = []
|
# answer_text = []
|
||||||
|
#
|
||||||
view_all_results = False
|
# view_all_results = False
|
||||||
if request.user.groups.filter(name="view_all_results").exists():
|
# if request.user.groups.filter(name="view_all_results").exists():
|
||||||
view_all_results = True
|
# view_all_results = True
|
||||||
|
#
|
||||||
for q in questions:
|
# for q in questions:
|
||||||
# Get user answer
|
# # Get user answer
|
||||||
user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
|
# user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
|
||||||
|
#
|
||||||
if not user_answer or user_answer is None:
|
# if not user_answer or user_answer is None:
|
||||||
# skip if no answer
|
# # skip if no answer
|
||||||
# answers_marks.append("")
|
# # answers_marks.append("")
|
||||||
# answers.append("")
|
# # answers.append("")
|
||||||
answer_score = 4
|
# answer_score = 4
|
||||||
# ans = "Not answered"
|
# # ans = "Not answered"
|
||||||
answer_text.append(
|
# answer_text.append(
|
||||||
(
|
# (
|
||||||
("Not answered"),
|
# ("Not answered"),
|
||||||
("Not answered"),
|
# ("Not answered"),
|
||||||
("Not answered"),
|
# ("Not answered"),
|
||||||
("Not answered"),
|
# ("Not answered"),
|
||||||
("Not answered"),
|
# ("Not answered"),
|
||||||
)
|
# )
|
||||||
)
|
# )
|
||||||
else:
|
# else:
|
||||||
answer_score = user_answer.get_answer_score()
|
# answer_score = user_answer.get_answer_score()
|
||||||
|
#
|
||||||
answer_text.append(
|
# answer_text.append(
|
||||||
(
|
# (
|
||||||
user_answer.answer_observations,
|
# user_answer.answer_observations,
|
||||||
user_answer.answer_interpretation,
|
# user_answer.answer_interpretation,
|
||||||
user_answer.answer_principle_diagnosis,
|
# user_answer.answer_principle_diagnosis,
|
||||||
user_answer.answer_differential_diagnosis,
|
# user_answer.answer_differential_diagnosis,
|
||||||
user_answer.answer_management,
|
# user_answer.answer_management,
|
||||||
)
|
# )
|
||||||
)
|
# )
|
||||||
|
#
|
||||||
if not exam.publish_results and not view_all_results:
|
# if not exam.publish_results and not view_all_results:
|
||||||
answer_score = 0
|
# answer_score = 0
|
||||||
# answers.append(ans)
|
# # answers.append(ans)
|
||||||
answers_marks.append(answer_score)
|
# answers_marks.append(answer_score)
|
||||||
# answers_and_marks.append((ans, answer_score, correct_answer))
|
# # answers_and_marks.append((ans, answer_score, correct_answer))
|
||||||
|
#
|
||||||
answered = [i for i in answers_marks if i != ""]
|
# answered = [i for i in answers_marks if i != ""]
|
||||||
if "" in answers_marks:
|
# if "" in answers_marks:
|
||||||
total_score = sum(answered)
|
# total_score = sum(answered)
|
||||||
unmarked_number = len(answers_marks) - len(answered)
|
# unmarked_number = len(answers_marks) - len(answered)
|
||||||
total_score = "{} ({} unmarked)".format(total_score, unmarked_number)
|
# total_score = "{} ({} unmarked)".format(total_score, unmarked_number)
|
||||||
normalised_score = "Not available"
|
# normalised_score = "Not available"
|
||||||
else:
|
# else:
|
||||||
total_score = sum(answered)
|
# total_score = sum(answered)
|
||||||
normalised_score = normaliseScore(total_score)
|
# normalised_score = normaliseScore(total_score)
|
||||||
|
#
|
||||||
max_score = len(questions) * 8
|
# max_score = len(questions) * 8
|
||||||
|
#
|
||||||
return render(
|
# return render(
|
||||||
request,
|
# request,
|
||||||
"longs/exam_scores_user.html",
|
# "longs/exam_scores_user.html",
|
||||||
{
|
# {
|
||||||
"exam": exam,
|
# "exam": exam,
|
||||||
"cid": cid,
|
# "cid": cid,
|
||||||
"passcode": passcode,
|
# "passcode": passcode,
|
||||||
"questions": questions,
|
# "questions": questions,
|
||||||
# "answers": answers,
|
# # "answers": answers,
|
||||||
"answers_marks": answers_marks,
|
# "answers_marks": answers_marks,
|
||||||
"total_score": total_score,
|
# "total_score": total_score,
|
||||||
"normalised_score": normalised_score,
|
# "normalised_score": normalised_score,
|
||||||
"max_score": max_score,
|
# "max_score": max_score,
|
||||||
"answer_text": answer_text,
|
# "answer_text": answer_text,
|
||||||
# "answers_and_marks": answers_and_marks,
|
# # "answers_and_marks": answers_and_marks,
|
||||||
"view_all_results": view_all_results,
|
# "view_all_results": view_all_results,
|
||||||
},
|
# },
|
||||||
)
|
# )
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
|||||||
+3
-5
@@ -12,7 +12,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from sortedm2m.fields import SortedManyToManyField
|
from sortedm2m.fields import SortedManyToManyField
|
||||||
|
|
||||||
from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionNote, UserAnswerBase, UserUserGroup
|
from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionBase, QuestionNote, UserAnswerBase, UserUserGroup
|
||||||
|
|
||||||
import reversion
|
import reversion
|
||||||
|
|
||||||
@@ -24,7 +24,7 @@ class Category(models.Model):
|
|||||||
return self.category
|
return self.category
|
||||||
|
|
||||||
|
|
||||||
class Question(models.Model):
|
class Question(QuestionBase):
|
||||||
stem = models.TextField(
|
stem = models.TextField(
|
||||||
blank=False,
|
blank=False,
|
||||||
help_text="Stem of the question",
|
help_text="Stem of the question",
|
||||||
@@ -82,8 +82,6 @@ class Question(models.Model):
|
|||||||
help_text="Feedback for answer",
|
help_text="Feedback for answer",
|
||||||
)
|
)
|
||||||
|
|
||||||
created_date = models.DateTimeField(default=timezone.now)
|
|
||||||
|
|
||||||
author = models.ManyToManyField(
|
author = models.ManyToManyField(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
blank=True,
|
blank=True,
|
||||||
@@ -95,7 +93,7 @@ class Question(models.Model):
|
|||||||
Category, on_delete=models.SET_NULL, null=True, blank=True
|
Category, on_delete=models.SET_NULL, null=True, blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
notes = GenericRelation(QuestionNote)
|
#notes = GenericRelation(QuestionNote)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.stem
|
return self.stem
|
||||||
|
|||||||
+6
-10
@@ -29,6 +29,7 @@ from generic.models import (
|
|||||||
CidUser,
|
CidUser,
|
||||||
CidUserGroup,
|
CidUserGroup,
|
||||||
ExamUserStatus,
|
ExamUserStatus,
|
||||||
|
QuestionBase,
|
||||||
Site,
|
Site,
|
||||||
#Condition,
|
#Condition,
|
||||||
#Sign,
|
#Sign,
|
||||||
@@ -148,7 +149,7 @@ class Answer(models.Model):
|
|||||||
self.answer_compare = get_answer_compare(self.answer)
|
self.answer_compare = get_answer_compare(self.answer)
|
||||||
|
|
||||||
|
|
||||||
class Rapid(models.Model):
|
class Rapid(QuestionBase):
|
||||||
"""
|
"""
|
||||||
Django model that defines a rapid question.
|
Django model that defines a rapid question.
|
||||||
|
|
||||||
@@ -160,7 +161,6 @@ class Rapid(models.Model):
|
|||||||
|
|
||||||
question = models.TextField(null=True, blank=True)
|
question = models.TextField(null=True, blank=True)
|
||||||
history = models.TextField(null=True, blank=True)
|
history = models.TextField(null=True, blank=True)
|
||||||
feedback = models.TextField(null=True, blank=True)
|
|
||||||
|
|
||||||
normal = models.BooleanField(default=False, help_text="Tick if true")
|
normal = models.BooleanField(default=False, help_text="Tick if true")
|
||||||
|
|
||||||
@@ -213,8 +213,7 @@ class Rapid(models.Model):
|
|||||||
# help_text=
|
# help_text=
|
||||||
# "If we know the source of the image")
|
# "If we know the source of the image")
|
||||||
verified = models.BooleanField(default=False)
|
verified = models.BooleanField(default=False)
|
||||||
created_date = models.DateTimeField(default=timezone.now)
|
|
||||||
published_date = models.DateTimeField(blank=True, null=True)
|
|
||||||
author = models.ManyToManyField(
|
author = models.ManyToManyField(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
blank=True,
|
blank=True,
|
||||||
@@ -226,12 +225,6 @@ class Rapid(models.Model):
|
|||||||
default=False, help_text="Question has been scrapped and will not be shown"
|
default=False, help_text="Question has been scrapped and will not be shown"
|
||||||
)
|
)
|
||||||
|
|
||||||
open_access = models.BooleanField(
|
|
||||||
help_text="If a question should be freely available to browse", default=True
|
|
||||||
)
|
|
||||||
|
|
||||||
notes = GenericRelation(QuestionNote)
|
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("rapids:question_detail", kwargs={"pk": self.pk})
|
return reverse("rapids:question_detail", kwargs={"pk": self.pk})
|
||||||
|
|
||||||
@@ -852,6 +845,9 @@ class UserAnswer(UserAnswerBase):
|
|||||||
# s = s.translate(str.maketrans('', '', string.punctuation))
|
# s = s.translate(str.maketrans('', '', string.punctuation))
|
||||||
# return s
|
# return s
|
||||||
|
|
||||||
|
def get_answer(self):
|
||||||
|
return self.get_answer_string()
|
||||||
|
|
||||||
def get_answer_string(self):
|
def get_answer_string(self):
|
||||||
if self.normal:
|
if self.normal:
|
||||||
return "Normal"
|
return "Normal"
|
||||||
|
|||||||
+3
-5
@@ -11,7 +11,7 @@ from django.utils.translation import gettext_lazy as _
|
|||||||
|
|
||||||
from sortedm2m.fields import SortedManyToManyField
|
from sortedm2m.fields import SortedManyToManyField
|
||||||
|
|
||||||
from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionNote, UserAnswerBase, UserUserGroup
|
from generic.models import CidUser, CidUserGroup, ExamBase, ExamUserStatus, QuestionBase, QuestionNote, UserAnswerBase, UserUserGroup
|
||||||
|
|
||||||
import reversion
|
import reversion
|
||||||
|
|
||||||
@@ -25,7 +25,7 @@ class Category(models.Model):
|
|||||||
return self.category
|
return self.category
|
||||||
|
|
||||||
|
|
||||||
class Question(models.Model):
|
class Question(QuestionBase):
|
||||||
stem = models.TextField(
|
stem = models.TextField(
|
||||||
blank=False,
|
blank=False,
|
||||||
help_text="Stem of the question",
|
help_text="Stem of the question",
|
||||||
@@ -82,8 +82,6 @@ class Question(models.Model):
|
|||||||
max_length=20, choices=BEST_ANSWER_CHOICES, help_text="The correct answer"
|
max_length=20, choices=BEST_ANSWER_CHOICES, help_text="The correct answer"
|
||||||
)
|
)
|
||||||
|
|
||||||
created_date = models.DateTimeField(default=timezone.now)
|
|
||||||
|
|
||||||
author = models.ManyToManyField(
|
author = models.ManyToManyField(
|
||||||
settings.AUTH_USER_MODEL,
|
settings.AUTH_USER_MODEL,
|
||||||
blank=True,
|
blank=True,
|
||||||
@@ -95,7 +93,7 @@ class Question(models.Model):
|
|||||||
Category, on_delete=models.SET_NULL, null=True, blank=True
|
Category, on_delete=models.SET_NULL, null=True, blank=True
|
||||||
)
|
)
|
||||||
|
|
||||||
notes = GenericRelation(QuestionNote)
|
#notes = GenericRelation(QuestionNote)
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.stem
|
return self.stem
|
||||||
|
|||||||
Reference in New Issue
Block a user