Add Crispy Forms integration to QuestionForm and update question_form template for improved layout and usability

This commit is contained in:
Ross
2025-11-03 13:39:35 +00:00
parent 3a5ceabff0
commit 6d02b35f86
3 changed files with 69 additions and 19 deletions
+34
View File
@@ -24,6 +24,8 @@ from django.forms.widgets import RadioSelect, TextInput, Textarea
from tinymce.widgets import TinyMCE
from dal import autocomplete
from crispy_forms.helper import FormHelper
from crispy_forms.layout import Layout, Fieldset, Row, Column, Submit
class UserAnswerForm(ModelForm):
@@ -105,6 +107,38 @@ class QuestionForm(ModelForm):
widget=FilteredSelectMultiple(verbose_name="Exams", is_stacked=False),
)
# Crispy Forms helper and layout
self.helper = FormHelper()
self.helper.form_method = "post"
self.helper.form_enctype = "multipart/form-data"
self.helper.template_pack = "bootstrap5"
self.helper.layout = Layout(
Fieldset(
"Question",
"title",
"stem",
),
Fieldset(
"Answers",
Row(Column("a_answer", css_class="col-6"), Column("a_feedback", css_class="col-6")),
Row(Column("b_answer", css_class="col-6"), Column("b_feedback", css_class="col-6")),
Row(Column("c_answer", css_class="col-6"), Column("c_feedback", css_class="col-6")),
Row(Column("d_answer", css_class="col-6"), Column("d_feedback", css_class="col-6")),
Row(Column("e_answer", css_class="col-6"), Column("e_feedback", css_class="col-6")),
"best_answer",
),
Fieldset(
"Feedback",
"feedback",
),
Fieldset(
"Metadata",
Row(Column("category", css_class="col-6"), Column("exams", css_class="col-6")),
Row(Column("open_access", css_class="col-4"), Column("frcr_appropriate", css_class="col-4")),
),
)
self.helper.add_input(Submit("submit", "Submit", css_class="btn btn-primary"))
def save(self, commit=True):
# Get the unsaved Pizza instance
instance = ModelForm.save(self, False)
+28 -13
View File
@@ -2,6 +2,7 @@
{% load static %}
{% load partials %}
{% load crispy_forms_tags %}
{% block js %}
<!-- <script type="text/javascript" src="/admin/jsi18n/"></script> -->
@@ -11,19 +12,33 @@
{{ form.media }}
{% endblock %}
{% block content %}
<div class="d-flex justify-content-between align-items-start mb-3 flex-column flex-md-row">
<div>
<h2>Submit Question</h2>
<div class="container py-3">
<div class="d-flex justify-content-between align-items-start mb-3 flex-column flex-md-row">
<div>
<h2 class="h4 mb-2">Submit Question</h2>
</div>
{% if question %}
{% include 'sbas/question_detail.html#links-partial' %}
{% endif %}
</div>
<div class="card">
<div class="card-body">
<form action="" method="post" enctype="multipart/form-data" id="anatomyquestion-form">
{% csrf_token %}
{{ form.media }}
<div class="mb-3">
{% crispy form %}
</div>
<div class="d-grid gap-2 d-md-flex justify-content-md-end">
<button type="submit" class="btn btn-primary">Submit</button>
<a href="{% url 'sbas:index' %}" class="btn btn-outline-secondary">Cancel</a>
</div>
</form>
</div>
</div>
{% if question %}
{% include 'sbas/question_detail.html#links-partial' %}
{% endif %}
</div>
<form action="" method="post" enctype="multipart/form-data" id="anatomyquestion-form">
{% csrf_token %}
<table>{{ form.as_table }}</table>
<input type="submit" class="submit-button" value="Submit" name="submit" />
</form>
{% endblock %}
+7 -6
View File
@@ -334,6 +334,7 @@ document.addEventListener('DOMContentLoaded', function() {
//}
// fallback to any table on the page that looks like it has selection
var any = document.querySelector('table.js-row-selectable') //|| Array.from(document.querySelectorAll('table')).find(function(t){ return t.querySelector && (t.querySelector('input[name="selection"]') || t.querySelector('input[type="checkbox"]')); });
console.log('findTableForControl fallback', any);
return any || null;
}
@@ -374,12 +375,12 @@ document.addEventListener('DOMContentLoaded', function() {
container.parentNode.insertBefore(wrapper, container);
}
// Create controls for any table that looks selectable but lacks a control block
Array.from(document.querySelectorAll('table')).forEach(function(t){
if (t.querySelector && (t.querySelector('input[name="selection"]') || t.querySelector('input[type="checkbox"]'))) {
ensureControlsForTable(t);
}
});
//// Create controls for any table that looks selectable but lacks a control block
//Array.from(document.querySelectorAll('table')).forEach(function(t){
// if (t.querySelector && (t.querySelector('input[name="selection"]') || t.querySelector('input[type="checkbox"]'))) {
// ensureControlsForTable(t);
// }
//});
// For every toggle button (supports both unsuffixed and suffixed IDs)
document.querySelectorAll('button[id^="toggle-row-selection"]').forEach(function(toggleBtn) {