I am trying to create an interface for a teacher to set homework tasks. This homework includes a student, a chapter, and questions belonging to a selected chapter. Therein lies my problem, I would like for my chapter dropdown to limit the selection from my question dropdown.
Here is the current model, I added a chapter to simplify this process however ideally the chapter is not a necessary part of the homework, it only serves as a filter for the questions.
class Homework(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
chapter = models.ForeignKey(
Chapter, on_delete=models.SET_NULL, null=True, related_name="chapter_homework"
)
question = models.ForeignKey(
Question, on_delete=models.CASCADE, related_name="homework"
)
agenda = models.ForeignKey(
Agenda, on_delete=models.CASCADE, related_name="homeworks"
)
This is the CreationView I have modified :
class HomeworkCreationView(CreateView):
template_name = "agenda/homework_create.html"
form_class = HomeworkForm
success_url = reverse_lazy("agenda:create_homework")
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['chapters'] = Chapter.objects.filterByAuthor(self.request.user)
return context
def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs["user"] = self.request.user
return kwargs
And this is a function based view which is meant to asynchronously update the question choices :
def loadQuestions(request):
chapter_id = request.GET.get('chapter')
questions = Question.objects.filterByChapterID(chapter_id).order_by('title')
return render(request, 'agenda/question_dropdown_list_options.html', {'questions':questions})
Here is the form :
class HomeworkForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
user = kwargs.pop("user", None)
super().__init__(*args, **kwargs)
teacher = user.userToTeacher()
self.fields["chapter"].queryset = Chapter.objects.filterByAuthor(teacher)
self.fields['question'].queryset = Question.objects.none()
class Meta:
model = Homework
fields = [ "chapter", "question", "due_date", "agenda"]
URLS.py :
app_name = "agenda"
urlpatterns = [
path("homework", HomeworkCreationView.as_view(), name="create_homework"),
path('homework/load-questions/', loadQuestions, name='load_questions'),
]
Here is the HTML and JS for the form page homework_create.html :
{% extends "base.html" %}
{% block title %}Create Homework{% endblock %}
{% block content %}
<h1>Give your students homework</h1>
<p>Choose a chapter and then select a question to add to your students agenda</p>
<form method="post" id="homeworkForm" data-questions-url="{% url 'agenda:load_questions' %}">
{% csrf_token %}
<table>
{{ form.as_table }}
</table>
<button type="submit">Save</button>
</form>
{% endblock %}
<script>
document.getElementById("id_chapter").addEventListener("change", function() {
var formElement = document.getElementById("homeworkForm");
var url = formElement.getAttribute("data-questions-url");
var chapterID = this.value;
var xhr = new XMLHttpRequest();
xhr.open("GET", url + "?chapter=" + chapterID, true);
xhr.onload = function() {
if (xhr.status === 200) {
document.getElementById("id_question").innerHTML = xhr.responseText;
}
};
xhr.send();
});
</script>
Finally here is the question_dropdown_list_options.html used for loading the questions :
<option value="">---------</option>
{% for question in questions %}
<option value="{{ question.id }}">{{ question.title }}</option>
{% endfor %}
I have found multiple tutorials and solutions that I can't quite get to work using simple Django form template. I'd also like to use "vanilla" JS (no ajax or jquery). Finally I have seen smart-select is an option but I would like to keep my models unchanged apart for getting rid of chapter in homework if possible.