Skip to content

Commit 6d49199

Browse files
committed
basic form for bulk editing option scores
Add a view to allow all the scores for questions in a section to be edited in one go. Fixes #106
1 parent a803a31 commit 6d49199

File tree

6 files changed

+163
-1
lines changed

6 files changed

+163
-1
lines changed

ceuk-marking/urls.py

+20-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,15 @@
1919
from django.contrib import admin
2020
from django.urls import include, path
2121

22-
from crowdsourcer.views import audit, marking, progress, rightofreply, stats, volunteers
22+
from crowdsourcer.views import (
23+
audit,
24+
marking,
25+
progress,
26+
questions,
27+
rightofreply,
28+
stats,
29+
volunteers,
30+
)
2331

2432
session_patterns = [
2533
# home page
@@ -304,6 +312,17 @@
304312
volunteers.VolunteerEditView.as_view(),
305313
name="edit_volunteer",
306314
),
315+
# question management
316+
path(
317+
"questions/options/<section_name>/",
318+
questions.OptionsView.as_view(),
319+
name="edit_options",
320+
),
321+
path(
322+
"questions/sections/",
323+
questions.SectionList.as_view(),
324+
name="question_sections",
325+
),
307326
]
308327

309328
urlpatterns = [

crowdsourcer/forms.py

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
URLField,
2121
formset_factory,
2222
inlineformset_factory,
23+
modelformset_factory,
2324
)
2425

2526
import pandas as pd
@@ -573,3 +574,8 @@ def __init__(self, properties: {}, **kwargs):
573574
required=False,
574575
widget=Textarea,
575576
)
577+
578+
579+
OptionFormset = modelformset_factory(
580+
Option, fields=["score"], extra=0, can_delete=False
581+
)

crowdsourcer/templates/crowdsourcer/base.html

+3
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,9 @@ <h2 class="navbar-text fs-6 mb-0">Admin</h2>
145145
<li class="nav-item dropdown">
146146
<a class="nav-link" href="{% session_url 'list_volunteers' %}">Volunteers</a>
147147
</li>
148+
<li class="nav-item dropdown">
149+
<a class="nav-link" href="{% session_url 'question_sections' %}">Scores</a>
150+
</li>
148151
{% endif %}
149152
</ul>
150153
</div>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{% extends 'crowdsourcer/base.html' %}
2+
3+
{% load crowdsourcer_tags django_bootstrap5 static %}
4+
5+
{% block content %}
6+
{% if show_login %}
7+
<h1 class="mb-4">Sign in</h1>
8+
<a href="{% url 'login' %}">Sign in</a>
9+
{% else %}
10+
<h3 class="mb-4">Scores for {{ section.title }} answers</h3>
11+
12+
13+
<form action="" method="post">
14+
{% csrf_token %}
15+
{{ form.management_form }}
16+
<div class="container">
17+
<div class="row border-bottom">
18+
<div class="col-sm">
19+
Description
20+
</div>
21+
22+
<div class="col-sm">
23+
Score
24+
</div>
25+
</div>
26+
{% for option_form in form %}
27+
{% ifchanged option_form.instance.question.number_and_part %}
28+
<fieldset class="pt-1">
29+
<h5>
30+
{{ option_form.instance.question.number_and_part }}
31+
{{ option_form.instance.question.description }}
32+
</h5>
33+
{% endifchanged %}
34+
<div class="row py-0">
35+
<div class="col-sm">
36+
<div class="mb-dd-4">
37+
{{ option_form.instance.description }}
38+
</div>
39+
</div>
40+
41+
<div class="col-sm">
42+
{{ option_form.score }}
43+
</div>
44+
</div>
45+
{{ option_form.id }}
46+
{% ifchanged option_form.instance.question.number_and_part %}
47+
</fieldset>
48+
{% endifchanged %}
49+
{% endfor %}
50+
</div>
51+
<input type="submit" class="btn btn-primary" value="Update">
52+
</form>
53+
54+
{% endif %}
55+
{% endblock %}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{% extends 'crowdsourcer/base.html' %}
2+
3+
{% load crowdsourcer_tags %}
4+
5+
{% block content %}
6+
{% if show_login %}
7+
<h1 class="mb-4">Sign in</h1>
8+
<a href="{% url 'login' %}">Sign in</a>
9+
{% else %}
10+
<div class="d-md-flex align-items-center mb-4">
11+
<h1 class="mb-md-0 me-md-auto">Sections</h1>
12+
</div>
13+
14+
<ul>
15+
{% for section in sections %}
16+
<li><a href="{% session_url 'edit_options' section.title %}">{{ section.title }}</li>
17+
{% endfor %}
18+
</ul>
19+
{% endif %}
20+
{% endblock %}

crowdsourcer/views/questions.py

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from django.contrib.auth.mixins import UserPassesTestMixin
2+
from django.shortcuts import get_object_or_404
3+
from django.urls import reverse
4+
from django.views.generic import FormView, ListView
5+
6+
from crowdsourcer.forms import OptionFormset
7+
from crowdsourcer.models import Option, Section
8+
9+
10+
class SectionList(ListView):
11+
template_name = "crowdsourcer/questions/sections.html"
12+
context_object_name = "sections"
13+
14+
def get_queryset(self):
15+
return Section.objects.filter(marking_session=self.request.current_session)
16+
17+
18+
class OptionsView(UserPassesTestMixin, FormView):
19+
template_name = "crowdsourcer/questions/options.html"
20+
form_class = OptionFormset
21+
22+
def test_func(self):
23+
return self.request.user.has_perm("crowdsourcer.can_manage_users")
24+
25+
def get_success_url(self):
26+
return reverse(
27+
"session_urls:edit_options",
28+
kwargs={
29+
"marking_session": self.request.current_session.label,
30+
"section_name": "Buildings & Heating",
31+
},
32+
)
33+
34+
def get_form(self):
35+
self.section = get_object_or_404(
36+
Section,
37+
title=self.kwargs["section_name"],
38+
marking_session=self.request.current_session,
39+
)
40+
41+
options = (
42+
Option.objects.filter(
43+
question__section=self.section,
44+
)
45+
.order_by("question__number", "question__number_part", "ordering")
46+
.select_related("question")
47+
)
48+
return self.form_class(queryset=options, **self.get_form_kwargs())
49+
50+
def get_context_data(self, **kwargs):
51+
context = super().get_context_data(**kwargs)
52+
53+
context["section"] = self.section
54+
55+
return context
56+
57+
def form_valid(self, form):
58+
form.save()
59+
return super().form_valid(form)

0 commit comments

Comments
 (0)