Add AddExamForm and update exam_edit_fragment for exam management

This commit is contained in:
Ross
2026-02-16 11:21:51 +00:00
parent fb9952e7aa
commit 0718ea82b2
2 changed files with 65 additions and 32 deletions
@@ -0,0 +1,23 @@
{% load static %}
<div id="exam-list">
<form hx-post="{% url 'anatomy:question_add_exam' question_id=question.pk %}" hx-target="#exam-list" hx-swap="innerHTML">
{% csrf_token %}
<div class="input-group mb-2">
{{ form.exam }}
<button class="btn btn-sm btn-primary" type="submit">Add</button>
<button type="button" class="btn btn-sm btn-outline-secondary" onclick="document.getElementById('exam-list').innerHTML='';">Close</button>
</div>
</form>
<div class="mb-2 small">Current exams:
{% for exam in question.exams.all %}
<form class="d-inline me-1" hx-post="{% url 'anatomy:question_add_exam' question_id=question.pk %}" hx-target="#exam-list" hx-swap="innerHTML">
{% csrf_token %}
<input type="hidden" name="exam_id" value="{{ exam.id }}">
<input type="hidden" name="remove" value="true">
<button class="btn btn-sm btn-outline-danger mb-1" type="submit" hx-confirm="Are you sure you want to remove this exam?">{{ exam }}</button>
</form>
{% empty %}
<span class="text-muted">No exams</span>
{% endfor %}
</div>
</div>
+42 -32
View File
@@ -59,6 +59,21 @@ from .models import (
# HalfMarkAnswers,
# IncorrectAnswers,
)
from generic.widgets import ExamSearchWidget
class AddExamForm(forms.Form):
exam = forms.ModelChoiceField(queryset=Exam.objects.none(), required=True, widget=ExamSearchWidget(exam_model=Exam), label="Exam to add")
def __init__(self, *args, user=None, **kwargs):
super().__init__(*args, **kwargs)
if user is None:
qs = Exam.objects.none()
elif user.groups.filter(name="anatomy_checker").exists():
qs = Exam.objects.all()
else:
qs = Exam.objects.filter(author__id=user.id) | Exam.objects.filter(open_access=True)
self.fields["exam"].queryset = qs.distinct()
from generic.models import CidUser, Examination
from generic.views import AuthorRequiredMixin, ExamCloneMixin, ExamCreateBase, ExamDeleteBase, ExamGroupsUpdateBase, ExamUpdateBase, ExamViews, GenericViewBase, UpdateQuestionMixin
from reversion.views import RevisionMixin
@@ -1627,44 +1642,39 @@ def question_add_exam(request, question_id: int):
return HttpResponse("Invalid permissions", status=403)
if request.POST:
# POST: handle add/remove; if exam_id provided use existing behaviour
if request.method == "POST":
exam_id = request.POST.get("exam_id", None)
if exam_id is None:
return HttpResponse("No exam id provided", status=400)
if exam_id:
exam = get_object_or_404(Exam, pk=exam_id)
if request.POST.get("remove", False) == "true":
question.exams.remove(exam)
else:
question.exams.add(exam)
exam = get_object_or_404(Exam, pk=exam_id)
# return updated fragment
form = AddExamForm(user=request.user)
return render(request, "anatomy/partials/exam_edit_fragment.html", {"form": form, "question": question})
if request.POST.get("remove", False) == "true":
question.exams.remove(exam)
return HttpResponse("Question removed from exam.")
# else try to process from the search form
form = AddExamForm(request.POST, user=request.user)
if form.is_valid():
exam = form.cleaned_data.get("exam")
if request.POST.get("remove", False) == "true":
question.exams.remove(exam)
else:
question.exams.add(exam)
form = AddExamForm(user=request.user)
return render(request, "anatomy/partials/exam_edit_fragment.html", {"form": form, "question": question})
else:
question.exams.add(exam)
# render form with errors
return render(request, "anatomy/partials/exam_edit_fragment.html", {"form": form, "question": question})
return HttpResponse("Question added to exam.")
else:
# Return a list of exams that we can add to the question
exams = Exam.objects.filter(author=request.user)
exams = exams.difference(question.exams.all())
if not exams:
return HttpResponse("No exams available to add")
html = "Exams to add to question: <br>"
for exam in exams:
html = html + (f"<span id='htmx-exam-list'><form><input name='exam_id' value='{exam.id}' type='hidden'><button hx-post=\"{request.path}\""
f">{exam.name}: {exam.id}</button></form>"
)
html = html + "<br>Exams to remove from question: <br>"
for exam in question.exams.all():
html = html + (f"<span id='htmx-exam-list'><form><input name='exam_id' value='{exam.id}' type='hidden'><input name='remove' value='true' type='hidden'><button hx-post=\"{request.path}\""
f"hx-confirm='Are you sure you want to remove this exam from the question?'"
f">{exam.name}: {exam.id}</button></form>"
)
html = html + "<button _='on click remove #htmx-exam-list'>Cancel</button>"
return HttpResponse(mark_safe(html))
# GET: render the fragment with the add form and current exams
form = AddExamForm(user=request.user)
return render(request, "anatomy/partials/exam_edit_fragment.html", {"form": form, "question": question})
raise PermissionDenied()