indici/src/core/views.py
Nathan Chapman b1bbb2b1c2 Fixes
2022-07-27 16:21:07 -06:00

700 lines
20 KiB
Python

import datetime as dt
from django.conf import settings
from django.utils import timezone
from django.db import models
from django.shortcuts import render, reverse, redirect, get_object_or_404
from django.urls import reverse, reverse_lazy
from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView
from django.views.generic.list import ListView
from django.views.generic.dates import YearArchiveView
from django.views.generic.edit import (
FormView, CreateView, UpdateView, DeleteView, FormMixin
)
from django.contrib import messages
from django.contrib.auth.mixins import (
LoginRequiredMixin, PermissionRequiredMixin
)
from django.contrib.messages.views import SuccessMessageMixin
from django.contrib.contenttypes.models import ContentType
from django.db.models import (
Exists, OuterRef, Prefetch, Subquery, Count, Sum, Avg, F, Q, Value
)
from .models import (
SchoolYear,
StudentTag,
Student,
Subject,
Tag,
Component,
Score,
SchoolDay,
AttendanceEntry,
)
from .forms import (
SchoolYearCreateForm,
ComponentCreateForm,
SchoolDayForm,
AttendanceEntryForm
)
class TodayView(LoginRequiredMixin, TemplateView):
template_name = 'core/today.html'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
today = timezone.localtime(timezone.now()).date()
enddate = today + dt.timedelta(days=7)
context['birthdays'] = Student.objects.filter(
dob__month=today.month,
dob__day__range=[today.day, enddate.day]
).order_by('dob')
context['components'] = Component.objects.filter(
due_date=today
).select_related('subject')
context['attendance'] = SchoolDay.objects.filter(
date=today
).prefetch_related('attendanceentry_set', 'attendanceentry_set__student')
context['ungraded_components'] = Component.objects.filter(
due_date__lte=today,
finished_grading=False
).select_related('subject')
return context
class SchoolYearListView(LoginRequiredMixin, ListView):
model = SchoolYear
paginate_by = 10
def get_queryset(self):
queryset = SchoolYear.objects.annotate(
models.Count('student', distinct=True),
models.Count('subject', distinct=True)
).order_by('-year')
return queryset
class SchoolYearCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = SchoolYear
success_message = 'SchoolYear created.'
form_class = SchoolYearCreateForm
template_name_suffix = '_create_form'
class SchoolYearDetailView(LoginRequiredMixin, DetailView):
model = SchoolYear
slug_url_kwarg = 'year'
slug_field = 'year'
class SchoolYearUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = SchoolYear
slug_url_kwarg = 'year'
slug_field = 'year'
success_message = 'SchoolYear saved.'
fields = '__all__'
class StudentListView(LoginRequiredMixin, ListView):
model = Student
paginate_by = 50
def get_queryset(self):
queryset = Student.objects.filter(
school_year__year=self.kwargs['year']
)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class StudentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Student
success_message = 'Student created.'
template_name_suffix = '_create_form'
fields = [
'student_id',
'first_name',
'last_name',
'address',
'dob',
]
def form_valid(self, form):
form.instance.school_year = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return super().form_valid(form)
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(SchoolYear, year=self.kwargs['year'])
return context
class StudentDetailView(LoginRequiredMixin, DetailView):
model = Student
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
context['score_list'] = Score.objects.select_related(
'student'
).prefetch_related(
'component'
).select_related(
'component__subject'
).filter(
student=self.object
).order_by(
'component__subject',
'-component__due_date'
)
context['subject_list'] = Subject.objects.filter(
component__score__student=self.object
).annotate(
grade=Sum(F('component__score__value')),
grade_total=Sum('component__grade_total')
)
context['entry_list'] = AttendanceEntry.objects.select_related(
'school_day'
).filter(
student=self.object
).order_by('status', '-school_day__date').select_related('student')
return context
class StudentUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = Student
success_message = 'Student saved.'
fields = '__all__'
class StudentDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = Student
success_message = 'Student deleted.'
success_url = reverse_lazy('student-list')
class StudentTagListView(LoginRequiredMixin, ListView):
model = StudentTag
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class StudentTagCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = StudentTag
success_message = 'Tag created.'
template_name_suffix = '_create_form'
fields = '__all__'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def get_success_url(self):
return reverse('core:stag-list', kwargs={
'year': self.kwargs['year']
})
class StudentTagDetailView(LoginRequiredMixin, DetailView):
model = StudentTag
pk_url_kwarg = 'stag_pk'
context_object_name = 'tag'
def get_object(self):
queryset = StudentTag.objects.filter(
pk=self.kwargs.get(self.pk_url_kwarg)
).prefetch_related(
Prefetch(
'student_set',
queryset=Student.objects.filter(
school_year__year=self.kwargs['year']
)
)
)
obj = queryset.get()
return obj
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class StudentTagUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = StudentTag
pk_url_kwarg = 'stag_pk'
context_object_name = 'tag'
success_message = 'Tag saved.'
fields = '__all__'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def get_success_url(self):
return reverse('core:stag-list', kwargs={
'year': self.kwargs['year']
})
class StudentTagDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = StudentTag
pk_url_kwarg = 'stag_pk'
context_object_name = 'tag'
success_message = 'Tag deleted.'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def get_success_url(self):
return reverse('core:stag-list', kwargs={
'year': self.kwargs['year']
})
class SubjectListView(LoginRequiredMixin, ListView):
model = Subject
paginate_by = 50
def get_queryset(self):
queryset = Subject.objects.filter(
school_year__year=self.kwargs['year']
).annotate(
models.Count('component')
).order_by('name')
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class SubjectCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Subject
success_message = 'Subject created.'
template_name_suffix = '_create_form'
fields = [
'name',
'description'
]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def form_valid(self, form):
form.instance.school_year = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return super().form_valid(form)
class SubjectDetailView(LoginRequiredMixin, DetailView):
model = Subject
def get_object(self):
queryset = Subject.objects.filter(
pk=self.kwargs.get(self.pk_url_kwarg)
).prefetch_related(
Prefetch(
'component_set',
queryset=Component.objects.prefetch_related(
'score_set'
).annotate(
grade_avg_pre=Avg('score__value')
)
)
)
obj = queryset.get()
return obj
class SubjectUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = Subject
success_message = 'Subject saved.'
fields = '__all__'
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class SubjectDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = Subject
success_message = 'Subject deleted.'
success_url = reverse_lazy('subject-list')
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class ComponentListView(LoginRequiredMixin, ListView):
model = Component
class ComponentCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Component
success_message = 'Component created.'
template_name_suffix = '_create_form'
form_class = ComponentCreateForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
context['subject'] = get_object_or_404(
Subject, pk=self.kwargs['pk']
)
return context
def form_valid(self, form):
form.instance.school_year = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
form.instance.subject = get_object_or_404(
Subject, pk=self.kwargs['pk']
)
return super().form_valid(form)
class ComponentDetailView(LoginRequiredMixin, DetailView):
model = Component
pk_url_kwarg = 'component_pk'
def get_object(self):
queryset = Component.objects.filter(
pk=self.kwargs.get(self.pk_url_kwarg)
).prefetch_related(
Prefetch(
'score_set',
queryset=Score.objects.select_related('student')
),
'tags'
).annotate(
grade_avg_pre=Avg('score__value')
)
obj = queryset.get()
return obj
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
cscores = Score.objects.filter(
component=self.object,
student=OuterRef('pk')
)
context['scoreless'] = Student.objects.filter(
school_year__year=self.kwargs['year']
).exclude(
score__in=cscores
)
return context
class ComponentUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = Component
pk_url_kwarg = 'component_pk'
success_message = 'Component saved.'
fields = '__all__'
def get_success_url(self):
return reverse('core:component-detail', kwargs={
'year': self.object.subject.school_year.year,
'pk': self.object.subject.pk,
'component_pk': self.object.pk
})
class ComponentDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = Component
pk_url_kwarg = 'component_pk'
success_message = 'Component deleted.'
success_url = reverse_lazy('core:component-list')
class ComponentManagerView(LoginRequiredMixin, UpdateView):
model = Component
pk_url_kwarg = 'component_pk'
template_name_suffix = '_manager'
fields = ['finished_grading']
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
cscores = Score.objects.filter(
component=self.object,
student=OuterRef('pk')
)
context['student_list'] = Student.objects.filter(
school_year__year=self.kwargs['year']
).annotate(
cscore=Subquery(cscores.values('value')),
cscore_pk=Subquery(cscores.values('pk'))
)
return context
def get_success_url(self):
return reverse('core:component-detail', kwargs={
'year': self.object.subject.school_year.year,
'pk': self.object.subject.pk,
'component_pk': self.object.pk
})
def form_valid(self, form):
form.save()
for key, value in self.request.POST.items():
if 'student' in key and value:
s_pk = key.split('_')[1]
obj, created = Score.objects.update_or_create(
component=self.object,
student=Student.objects.get(pk=s_pk),
defaults={'value': value}
)
return super().form_valid(form)
class ScoreListView(LoginRequiredMixin, ListView):
model = Score
class ScoreCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = Score
success_message = 'Score created.'
template_name_suffix = '_create_form'
fields = '__all__'
class ScoreDetailView(LoginRequiredMixin, DetailView):
model = Score
class ScoreUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = Score
success_message = 'Score saved.'
fields = [
'component',
'value'
]
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class ScoreDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = Score
success_message = 'Score deleted.'
def get_success_url(self):
return reverse('core:schoolyear-detail', kwargs={
'year': self.kwargs['year']
})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class SchoolDayListView(LoginRequiredMixin, ListView):
model = SchoolDay
paginate_by = 7
def get_queryset(self):
queryset = SchoolDay.objects.filter(
school_year__year=self.kwargs['year']
)
return queryset
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class SchoolDayCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = SchoolDay
success_message = 'SchoolDay created.'
template_name_suffix = '_create_form'
form_class = SchoolDayForm
def get_initial(self):
today = timezone.localtime(timezone.now()).date()
initial = {
'date': today,
}
return initial
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['student_list'] = Student.objects.filter(
school_year__year=self.kwargs['year']
)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def form_valid(self, form):
form.instance.school_year = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
form.save()
for key, value in self.request.POST.items():
if 'student' in key:
s = key.split('_')[1]
AttendanceEntry.objects.create(
school_day=form.instance,
student=Student.objects.get(pk=s),
status=value,
)
return super().form_valid(form)
class SchoolDayDetailView(LoginRequiredMixin, DetailView):
model = SchoolDay
class SchoolDayUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = SchoolDay
success_message = 'SchoolDay saved.'
form_class = SchoolDayForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
def form_valid(self, form):
form.save()
for key, value in self.request.POST.items():
if 'student' in key:
s = key.split('_')[1]
AttendanceEntry.objects.filter(
school_day=self.object,
student=Student.objects.get(pk=s)
).update(status=value)
return super().form_valid(form)
class SchoolDayDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = SchoolDay
success_message = 'SchoolDay deleted.'
def get_success_url(self):
return reverse('core:schoolday-list', kwargs={
'year': self.kwargs['year']
})
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['school_year'] = get_object_or_404(
SchoolYear, year=self.kwargs['year']
)
return context
class AttendanceEntryListView(LoginRequiredMixin, ListView):
model = AttendanceEntry
class AttendanceEntryCreateView(LoginRequiredMixin, SuccessMessageMixin, CreateView):
model = AttendanceEntry
success_message = 'Entry created.'
template_name_suffix = '_create_form'
fields = '__all__'
class AttendanceEntryDetailView(LoginRequiredMixin, DetailView):
model = AttendanceEntry
pk_url_kwarg = 'entry_pk'
context_object_name = 'entry'
class AttendanceEntryUpdateView(LoginRequiredMixin, SuccessMessageMixin, UpdateView):
model = AttendanceEntry
pk_url_kwarg = 'entry_pk'
context_object_name = 'entry'
success_message = 'Entry saved.'
form_class = AttendanceEntryForm
def get_success_url(self):
return reverse('core:schoolday-detail', kwargs={
'year': self.kwargs['year'],
'pk': self.kwargs['pk']
})
class AttendanceEntryDeleteView(LoginRequiredMixin, SuccessMessageMixin, DeleteView):
model = AttendanceEntry
pk_url_kwarg = 'entry_pk'
context_object_name = 'entry'
success_message = 'Entry deleted.'
def get_success_url(self):
return reverse('core:schoolday-detail', kwargs={
'year': self.kwargs['year'],
'pk': self.kwargs['pk']
})