Merge branch 'master' of ssh://git.xkjq.uk:30001/ross/rad
This commit is contained in:
+10
-10
@@ -238,19 +238,19 @@ def loadJsonAnswer(answer):
|
|||||||
if (not isinstance(answer["cid"], int)) or (
|
if (not isinstance(answer["cid"], int)) or (
|
||||||
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
|
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
|
||||||
):
|
):
|
||||||
return JsonResponse({"success": False, "error": "cid or eid or answers not defined"})
|
return False, JsonResponse({"success": False, "error": "cid or eid or answers not defined"})
|
||||||
|
|
||||||
# The model should catch invalid data but this should be less intensive
|
# The model should catch invalid data but this should be less intensive
|
||||||
max_int = 999999999999999999999
|
max_int = 999999999999999999999
|
||||||
if answer["cid"] > max_int or eid > max_int:
|
if answer["cid"] > max_int or eid > max_int:
|
||||||
return JsonResponse({"success": False, "error": "invalid cid"})
|
return False, JsonResponse({"success": False, "error": "invalid cid"})
|
||||||
|
|
||||||
exam = get_object_or_404(Exam, pk=eid)
|
exam = get_object_or_404(Exam, pk=eid)
|
||||||
|
|
||||||
if not exam.active:
|
#if not exam.active:
|
||||||
return JsonResponse(
|
# return False, JsonResponse(
|
||||||
{"success": False, "error": "No active exam: {}".format(eid)}
|
# {"success": False, "error": "No active exam: {}".format(eid)}
|
||||||
)
|
# )
|
||||||
|
|
||||||
exiting_answers = CidUserAnswer.objects.filter(
|
exiting_answers = CidUserAnswer.objects.filter(
|
||||||
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
|
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
|
||||||
@@ -272,7 +272,7 @@ def loadJsonAnswer(answer):
|
|||||||
ans.full_clean()
|
ans.full_clean()
|
||||||
ans.save()
|
ans.save()
|
||||||
|
|
||||||
return True
|
return True, None
|
||||||
|
|
||||||
|
|
||||||
#@csrf_exempt
|
#@csrf_exempt
|
||||||
@@ -453,7 +453,7 @@ def exam_scores_cid(request, pk):
|
|||||||
questions = exam.exam_questions.all()
|
questions = exam.exam_questions.all()
|
||||||
|
|
||||||
cids = (
|
cids = (
|
||||||
CidUserAnswer.objects.filter(question__in=questions)
|
CidUserAnswer.objects.filter(question__in=questions, exam__id=pk)
|
||||||
.order_by("cid")
|
.order_by("cid")
|
||||||
.values_list("cid", flat=True)
|
.values_list("cid", flat=True)
|
||||||
.distinct()
|
.distinct()
|
||||||
@@ -473,7 +473,7 @@ def exam_scores_cid(request, pk):
|
|||||||
user_names[cid] = cid
|
user_names[cid] = cid
|
||||||
for q in questions:
|
for q in questions:
|
||||||
# Get user answer
|
# Get user answer
|
||||||
s = q.cid_user_answers.filter(cid=cid).first()
|
s = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
|
||||||
if not s:
|
if not s:
|
||||||
# skip if no answer
|
# skip if no answer
|
||||||
user_answers_marks[cid].append(0)
|
user_answers_marks[cid].append(0)
|
||||||
@@ -564,7 +564,7 @@ def exam_scores_cid_user(request, pk, sk):
|
|||||||
|
|
||||||
for q in questions:
|
for q in questions:
|
||||||
# Get user answer
|
# Get user answer
|
||||||
user_answer = q.cid_user_answers.filter(cid=cid).first()
|
user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
|
||||||
if not user_answer:
|
if not user_answer:
|
||||||
# skip if no answer
|
# skip if no answer
|
||||||
answers_marks.append(0)
|
answers_marks.append(0)
|
||||||
|
|||||||
+19
-8
@@ -157,6 +157,10 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
self.question_type = question_type
|
self.question_type = question_type
|
||||||
self.loadJsonAnswer = loadJsonAnswer
|
self.loadJsonAnswer = loadJsonAnswer
|
||||||
|
|
||||||
|
# THis may be better than check_user_access below
|
||||||
|
#group_map = {"rapids" : "rapid_checker", "anatomy" : "anatomy_checker", "longs":"long_checker"}
|
||||||
|
#exam_group = group_map[self.app_name]
|
||||||
|
|
||||||
def check_user_access(self, user):
|
def check_user_access(self, user):
|
||||||
"""Check if a user should be able to access a view
|
"""Check if a user should be able to access a view
|
||||||
|
|
||||||
@@ -174,6 +178,8 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
return False
|
return False
|
||||||
if self.app_name == "physics" and not user.groups.filter(name='physic_checker').exists():
|
if self.app_name == "physics" and not user.groups.filter(name='physic_checker').exists():
|
||||||
return False
|
return False
|
||||||
|
if self.app_name == "sbas" and not user.groups.filter(name='sba_checker').exists():
|
||||||
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -326,6 +332,7 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
|
|
||||||
questions = exam.exam_questions.all()
|
questions = exam.exam_questions.all()
|
||||||
|
|
||||||
|
# TODO: fix showing unmarked answer count from other exams...
|
||||||
return render(
|
return render(
|
||||||
request, "{}/mark_overview.html".format(self.app_name), {"exam": exam, "questions": questions}
|
request, "{}/mark_overview.html".format(self.app_name), {"exam": exam, "questions": questions}
|
||||||
)
|
)
|
||||||
@@ -384,7 +391,7 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
active_exams = {"exams": []}
|
active_exams = {"exams": []}
|
||||||
|
|
||||||
for exam in exams:
|
for exam in exams:
|
||||||
if exam.active:
|
if exam.active or self.check_user_access(request.user):
|
||||||
if exam.json_creation_time:
|
if exam.json_creation_time:
|
||||||
creation_time = exam.json_creation_time.isoformat()
|
creation_time = exam.json_creation_time.isoformat()
|
||||||
else:
|
else:
|
||||||
@@ -401,7 +408,8 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
"type": self.question_type,
|
"type": self.question_type,
|
||||||
"eid": "{}/{}".format(self.question_type, exam.pk),
|
"eid": "{}/{}".format(self.question_type, exam.pk),
|
||||||
"json_creation_time": creation_time,
|
"json_creation_time": creation_time,
|
||||||
"exam_json_id": exam.exam_json_id
|
"exam_json_id": exam.exam_json_id,
|
||||||
|
"exam_active": exam.active
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.question_type == "long":
|
if self.question_type == "long":
|
||||||
@@ -426,13 +434,15 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
n = 0
|
n = 0
|
||||||
|
|
||||||
for answer in json.loads(request.POST.get("answers")):
|
for answer in json.loads(request.POST.get("answers")):
|
||||||
ret = self.loadJsonAnswer(answer)
|
ret_status, ret = self.loadJsonAnswer(answer)
|
||||||
|
|
||||||
#if ret is not True:
|
#if ret is not True:
|
||||||
# return ret
|
# return ret
|
||||||
|
|
||||||
if ret:
|
if ret_status:
|
||||||
n = n + 1
|
n = n + 1
|
||||||
|
else:
|
||||||
|
return ret
|
||||||
|
|
||||||
# print(UserAnswer.objects.filter(exam__id=q["eid"]))
|
# print(UserAnswer.objects.filter(exam__id=q["eid"]))
|
||||||
# print(request.urlencode())
|
# print(request.urlencode())
|
||||||
@@ -446,17 +456,18 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
"""
|
"""
|
||||||
exam = get_object_or_404(self.Exam, pk=pk)
|
exam = get_object_or_404(self.Exam, pk=pk)
|
||||||
|
|
||||||
if not exam.active:
|
if not exam.active and not self.check_user_access(request.user):
|
||||||
raise Http404("No available exam")
|
raise Http404("No available exam")
|
||||||
|
|
||||||
exam_json = exam.get_exam_json(based=False)
|
exam_json = exam.get_exam_json(based=False)
|
||||||
|
#exam_json["exam_active"] = False
|
||||||
return JsonResponse(exam_json)
|
return JsonResponse(exam_json)
|
||||||
|
|
||||||
def exam_json(self, request, pk):
|
def exam_json(self, request, pk):
|
||||||
|
|
||||||
exam = get_object_or_404(self.Exam, pk=pk)
|
exam = get_object_or_404(self.Exam, pk=pk)
|
||||||
|
|
||||||
if not exam.active:
|
if not exam.active and not self.check_user_access(request.user):
|
||||||
raise Http404("No available exam")
|
raise Http404("No available exam")
|
||||||
|
|
||||||
|
|
||||||
@@ -504,7 +515,7 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
question = get_object_or_404(self.Question, pk=sk)
|
question = get_object_or_404(self.Question, pk=sk)
|
||||||
exam = get_object_or_404(self.Exam, pk=pk)
|
exam = get_object_or_404(self.Exam, pk=pk)
|
||||||
|
|
||||||
if not exam.active:
|
if not exam.active and not self.check_user_access(request.user):
|
||||||
raise Http404("No available exam")
|
raise Http404("No available exam")
|
||||||
|
|
||||||
|
|
||||||
@@ -520,7 +531,7 @@ class ExamViews(View, LoginRequiredMixin):
|
|||||||
question = get_object_or_404(self.Question, pk=sk)
|
question = get_object_or_404(self.Question, pk=sk)
|
||||||
exam = get_object_or_404(self.Exam, pk=pk)
|
exam = get_object_or_404(self.Exam, pk=pk)
|
||||||
|
|
||||||
if not exam.active:
|
if not exam.active and not self.check_user_access(request.user):
|
||||||
raise Http404("No available exam")
|
raise Http404("No available exam")
|
||||||
|
|
||||||
return redirect("{}:question_json_unbased".format(self.app_name), pk=sk)
|
return redirect("{}:question_json_unbased".format(self.app_name), pk=sk)
|
||||||
|
|||||||
@@ -32,9 +32,11 @@
|
|||||||
<br />
|
<br />
|
||||||
{% for series in question.series.all %}
|
{% for series in question.series.all %}
|
||||||
<div class="series-block">
|
<div class="series-block">
|
||||||
Series {{forloop.counter0 }}:<br />
|
Series {{forloop.counter }}:<br />
|
||||||
{{series.get_block}}
|
{{series.get_block}}
|
||||||
</div>
|
</div>
|
||||||
|
{% empty %}
|
||||||
|
No series
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
<div>
|
<div>
|
||||||
Author(s): {{question.get_authors}}
|
Author(s): {{question.get_authors}}
|
||||||
|
|||||||
@@ -49,7 +49,9 @@
|
|||||||
<button type="submit" name="next" class="save btn btn-default" title="Save answer and move to next question">Next answer</button>
|
<button type="submit" name="next" class="save btn btn-default" title="Save answer and move to next question">Next answer</button>
|
||||||
<!-- <button type="submit" name="skip" class="save btn btn-default">Skip</button> -->
|
<!-- <button type="submit" name="skip" class="save btn btn-default">Skip</button> -->
|
||||||
{% else %}
|
{% else %}
|
||||||
(no more answers for this question to mark)
|
{% if not unmarked %}
|
||||||
|
All question answers marker. <a href="{% url 'longs:mark_overview' pk=exam.pk %}">Return to marking overview</a>
|
||||||
|
{% endif %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+14
-12
@@ -571,21 +571,21 @@ def loadJsonAnswer(answer):
|
|||||||
if (not isinstance(answer["cid"], int)) or (
|
if (not isinstance(answer["cid"], int)) or (
|
||||||
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
|
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
|
||||||
):
|
):
|
||||||
return JsonResponse(
|
return False, JsonResponse(
|
||||||
{"success": False, "error": "cid or eid or answers not defined"}
|
{"success": False, "error": "cid or eid or answers not defined"}
|
||||||
)
|
)
|
||||||
|
|
||||||
# The model should catch invalid data but this should be less intensive
|
# The model should catch invalid data but this should be less intensive
|
||||||
max_int = 999999999999999999999
|
max_int = 999999999999999999999
|
||||||
if answer["cid"] > max_int or eid > max_int:
|
if answer["cid"] > max_int or eid > max_int:
|
||||||
return JsonResponse({"success": False, "error": "invalid cid"})
|
return False, JsonResponse({"success": False, "error": "invalid cid"})
|
||||||
|
|
||||||
exam = get_object_or_404(Exam, pk=eid)
|
exam = get_object_or_404(Exam, pk=eid)
|
||||||
|
|
||||||
if not exam.active:
|
#if not exam.active:
|
||||||
return JsonResponse(
|
# return False, JsonResponse(
|
||||||
{"success": False, "error": "No active exam: {}".format(eid)}
|
# {"success": False, "error": "No active exam: {}".format(eid)}
|
||||||
)
|
# )
|
||||||
|
|
||||||
exiting_answers = CidUserAnswer.objects.filter(
|
exiting_answers = CidUserAnswer.objects.filter(
|
||||||
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
|
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
|
||||||
@@ -627,7 +627,7 @@ def loadJsonAnswer(answer):
|
|||||||
ans.full_clean()
|
ans.full_clean()
|
||||||
ans.save()
|
ans.save()
|
||||||
|
|
||||||
return True
|
return True, None
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
@@ -650,7 +650,7 @@ def mark_answer(request, pk, sk, tk):
|
|||||||
raise Http404("Exam question does not exist")
|
raise Http404("Exam question does not exist")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
answer = question.cid_user_answers.get(cid=tk)
|
answer = question.cid_user_answers.get(cid=tk, exam__id=pk)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
raise Http404("User answer does not exist")
|
raise Http404("User answer does not exist")
|
||||||
|
|
||||||
@@ -678,6 +678,8 @@ def mark_answer(request, pk, sk, tk):
|
|||||||
|
|
||||||
if "next" in request.POST:
|
if "next" in request.POST:
|
||||||
return redirect("longs:mark_answer", pk=pk, sk=sk, tk=next_unmarked_id)
|
return redirect("longs:mark_answer", pk=pk, sk=sk, tk=next_unmarked_id)
|
||||||
|
if "save" in request.POST:
|
||||||
|
return redirect("longs:mark_answer", pk=pk, sk=sk, tk=tk)
|
||||||
#elif "previous" in request.POST:
|
#elif "previous" in request.POST:
|
||||||
# return redirect("longs:mark", pk=pk, sk=n - 1)
|
# return redirect("longs:mark", pk=pk, sk=n - 1)
|
||||||
|
|
||||||
@@ -720,7 +722,7 @@ def mark(request, pk, sk):
|
|||||||
raise Http404("Exam question does not exist")
|
raise Http404("Exam question does not exist")
|
||||||
|
|
||||||
|
|
||||||
user_answers = question.cid_user_answers.all()
|
user_answers = question.cid_user_answers.filter(exam__id=pk)
|
||||||
|
|
||||||
return render(
|
return render(
|
||||||
request,
|
request,
|
||||||
@@ -742,7 +744,7 @@ def exam_scores_cid(request, pk):
|
|||||||
questions = exam.exam_questions.all()
|
questions = exam.exam_questions.all()
|
||||||
|
|
||||||
cids = (
|
cids = (
|
||||||
CidUserAnswer.objects.filter(question__in=questions)
|
CidUserAnswer.objects.filter(question__in=questions, exam__id=pk)
|
||||||
.order_by("cid")
|
.order_by("cid")
|
||||||
.values_list("cid", flat=True)
|
.values_list("cid", flat=True)
|
||||||
.distinct()
|
.distinct()
|
||||||
@@ -762,7 +764,7 @@ def exam_scores_cid(request, pk):
|
|||||||
user_names[cid] = cid
|
user_names[cid] = cid
|
||||||
for q in questions:
|
for q in questions:
|
||||||
# Get user answer
|
# Get user answer
|
||||||
s = q.cid_user_answers.filter(cid=cid).first()
|
s = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
|
||||||
|
|
||||||
if not s:
|
if not s:
|
||||||
# skip if no answer, (score 4)
|
# skip if no answer, (score 4)
|
||||||
@@ -855,7 +857,7 @@ def exam_scores_cid_user(request, pk, sk):
|
|||||||
|
|
||||||
for q in questions:
|
for q in questions:
|
||||||
# Get user answer
|
# Get user answer
|
||||||
user_answer = q.cid_user_answers.filter(cid=cid).first()
|
user_answer = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
-7
@@ -245,19 +245,19 @@ def exam_take(request, pk):
|
|||||||
def loadJsonAnswer(answer):
|
def loadJsonAnswer(answer):
|
||||||
# As access is not restricted make sure the data appears valid
|
# As access is not restricted make sure the data appears valid
|
||||||
if (not isinstance(answer["cid"], int)) or (not isinstance(answer["eid"], int)):
|
if (not isinstance(answer["cid"], int)) or (not isinstance(answer["eid"], int)):
|
||||||
return JsonResponse({"success": False, "error": "invalid"})
|
return False, JsonResponse({"success": False, "error": "invalid"})
|
||||||
|
|
||||||
# The model should catch invalid data but this should be less intensive
|
# The model should catch invalid data but this should be less intensive
|
||||||
max_int = 10000000
|
max_int = 10000000
|
||||||
if answer["cid"] > max_int or answer["eid"] > max_int:
|
if answer["cid"] > max_int or answer["eid"] > max_int:
|
||||||
return JsonResponse({"success": False})
|
return False, JsonResponse({"success": False})
|
||||||
|
|
||||||
exam = get_object_or_404(Exam, pk=answer["eid"])
|
exam = get_object_or_404(Exam, pk=answer["eid"])
|
||||||
|
|
||||||
if not exam.active:
|
#if not exam.active:
|
||||||
return JsonResponse(
|
# return False, JsonResponse(
|
||||||
{"success": False, "error": "No active exam: {}".format(answer["eid"])}
|
# {"success": False, "error": "No active exam: {}".format(answer["eid"])}
|
||||||
)
|
# )
|
||||||
|
|
||||||
questions = defaultdict(dict)
|
questions = defaultdict(dict)
|
||||||
|
|
||||||
@@ -296,6 +296,6 @@ def loadJsonAnswer(answer):
|
|||||||
ans.full_clean()
|
ans.full_clean()
|
||||||
ans.save()
|
ans.save()
|
||||||
|
|
||||||
return True
|
return True, None
|
||||||
|
|
||||||
PhysicsExamViews = ExamViews(Exam, Question, "physics", "physics", loadJsonAnswer)
|
PhysicsExamViews = ExamViews(Exam, Question, "physics", "physics", loadJsonAnswer)
|
||||||
@@ -131,6 +131,11 @@ def active_exams(request):
|
|||||||
|
|
||||||
active_exams = {"exams": exams}
|
active_exams = {"exams": exams}
|
||||||
|
|
||||||
|
if request.user:
|
||||||
|
active_exams["user"] = request.user.username
|
||||||
|
else:
|
||||||
|
active_exams["user"] = False
|
||||||
|
|
||||||
return JsonResponse(active_exams)
|
return JsonResponse(active_exams)
|
||||||
|
|
||||||
def active_exams_unbased(request):
|
def active_exams_unbased(request):
|
||||||
|
|||||||
+10
-10
@@ -580,21 +580,21 @@ def loadJsonAnswer(answer):
|
|||||||
if (not isinstance(answer["cid"], int)) or (
|
if (not isinstance(answer["cid"], int)) or (
|
||||||
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
|
not isinstance(eid, int) or (not isinstance(answer["ans"], str))
|
||||||
):
|
):
|
||||||
return JsonResponse(
|
return False, JsonResponse(
|
||||||
{"success": False, "error": "cid or eid or answers not defined"}
|
{"success": False, "error": "cid or eid or answers not defined"}
|
||||||
)
|
)
|
||||||
|
|
||||||
# The model should catch invalid data but this should be less intensive
|
# The model should catch invalid data but this should be less intensive
|
||||||
max_int = 999999999999999999999
|
max_int = 999999999999999999999
|
||||||
if answer["cid"] > max_int or eid > max_int:
|
if answer["cid"] > max_int or eid > max_int:
|
||||||
return JsonResponse({"success": False, "error": "invalid cid"})
|
return False, JsonResponse({"success": False, "error": "invalid cid"})
|
||||||
|
|
||||||
exam = get_object_or_404(Exam, pk=eid)
|
exam = get_object_or_404(Exam, pk=eid)
|
||||||
|
|
||||||
if not exam.active:
|
#if not exam.active:
|
||||||
return JsonResponse(
|
# return False, JsonResponse(
|
||||||
{"success": False, "error": "No active exam: {}".format(eid)}
|
# {"success": False, "error": "No active exam: {}".format(eid)}
|
||||||
)
|
# )
|
||||||
|
|
||||||
exiting_answers = CidUserAnswer.objects.filter(
|
exiting_answers = CidUserAnswer.objects.filter(
|
||||||
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
|
question__id=answer["qid"], exam__id=eid, cid=answer["cid"]
|
||||||
@@ -631,7 +631,7 @@ def loadJsonAnswer(answer):
|
|||||||
ans.full_clean()
|
ans.full_clean()
|
||||||
ans.save()
|
ans.save()
|
||||||
|
|
||||||
return True
|
return True, None
|
||||||
|
|
||||||
|
|
||||||
# @user_passes_test(user_is_admin, login_url="/accounts/login")
|
# @user_passes_test(user_is_admin, login_url="/accounts/login")
|
||||||
@@ -787,7 +787,7 @@ def exam_scores_cid(request, pk):
|
|||||||
questions = exam.exam_questions.all()
|
questions = exam.exam_questions.all()
|
||||||
|
|
||||||
cids = (
|
cids = (
|
||||||
CidUserAnswer.objects.filter(question__in=questions)
|
CidUserAnswer.objects.filter(question__in=questions, exam__id=pk)
|
||||||
.order_by("cid")
|
.order_by("cid")
|
||||||
.values_list("cid", flat=True)
|
.values_list("cid", flat=True)
|
||||||
.distinct()
|
.distinct()
|
||||||
@@ -807,7 +807,7 @@ def exam_scores_cid(request, pk):
|
|||||||
user_names[cid] = cid
|
user_names[cid] = cid
|
||||||
for q in questions:
|
for q in questions:
|
||||||
# Get user answer
|
# Get user answer
|
||||||
s = q.cid_user_answers.filter(cid=cid).first()
|
s = q.cid_user_answers.filter(cid=cid, exam__id=pk).first()
|
||||||
|
|
||||||
if not s:
|
if not s:
|
||||||
# skip if no answer
|
# skip if no answer
|
||||||
@@ -901,7 +901,7 @@ def exam_scores_cid_user(request, pk, sk):
|
|||||||
|
|
||||||
for q in questions:
|
for q in questions:
|
||||||
# Get user answer
|
# Get user answer
|
||||||
user_answer = q.cid_user_answers.filter(cid=cid).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
|
||||||
|
|||||||
@@ -16,4 +16,5 @@
|
|||||||
{% if request.user.is_staff %}<a href="{% url 'admin:index'%}">Admin</a>{% endif %}
|
{% if request.user.is_staff %}<a href="{% url 'admin:index'%}">Admin</a>{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<p>A radiology resource</p>
|
<p>A radiology resource</p>
|
||||||
|
<p><a href="http://www.penracourses.org.uk/rts">RTS is available here</a></p>
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
Reference in New Issue
Block a user