From d8fc21cb2674d29492459f30d371f470f0e69eb6 Mon Sep 17 00:00:00 2001 From: Danil Andreev Date: Sun, 5 Feb 2023 19:23:01 +0300 Subject: [PATCH 1/3] SPORT-636: Add student manager --- adminpage/sport/admin/studentAdmin.py | 58 +++++++++++++-------------- adminpage/sport/models/student.py | 37 +++++++++++++++++ 2 files changed, 66 insertions(+), 29 deletions(-) diff --git a/adminpage/sport/admin/studentAdmin.py b/adminpage/sport/admin/studentAdmin.py index 44d1cbd9..368a78ab 100644 --- a/adminpage/sport/admin/studentAdmin.py +++ b/adminpage/sport/admin/studentAdmin.py @@ -49,15 +49,15 @@ def lookups(self, request, model_admin): def queryset(self, request, queryset): value = self.value() if value == 'less': - return queryset.filter(complex_hours__lt=-60) + return queryset.filter(hours__lt=-60) if value == '-31': - return queryset.filter(complex_hours__lt=-30).filter(complex_hours__gte=-60) + return queryset.filter(hours__lt=-30).filter(hours__gte=-60) if value == '-1': - return queryset.filter(complex_hours__lt=0).filter(complex_hours__gte=-30) + return queryset.filter(hours__lt=0).filter(hours__gte=-30) if value == '29': - return queryset.filter(complex_hours__lt=30).filter(complex_hours__gte=0) + return queryset.filter(hours__lt=30).filter(hours__gte=0) elif value == 'more': - return queryset.filter(complex_hours__gte=30) + return queryset.filter(hours__gte=30) return queryset @@ -80,7 +80,7 @@ class StudentResource(resources.ModelResource): widget=ForeignKeyWidget(Sport, "name"), ) - complex_hours = fields.Field(attribute='complex_hours', readonly=True) + hours = fields.Field(attribute='hours', readonly=True) def get_or_init_instance(self, instance_loader, row): student_group = get_or_create_student_group() @@ -138,7 +138,7 @@ class Meta: "student_status", "is_online", 'sport', - 'complex_hours', + 'hours', "telegram", ) import_id_fields = ("user",) @@ -234,7 +234,7 @@ def get_fields(self, request, obj=None): "course", "medical_group", "sport", - "complex_hours", + "hours", "student_status", "write_to_telegram", ) @@ -251,9 +251,9 @@ def write_to_telegram(self, obj): obj.telegram ) - def complex_hours(self, obj: Student): - return obj.complex_hours - complex_hours.admin_order_field = 'complex_hours' + def hours(self, obj: Student): + return obj.hours + hours.admin_order_field = 'hours' ordering = ( "user__first_name", @@ -278,24 +278,24 @@ def change_view(self, request, object_id, form_url='', extra_context=None): self.inlines = (ViewAttendanceInline,) return super().change_view(request, object_id, form_url, extra_context) - def get_queryset(self, request): - qs = super().get_queryset(request) - - qs = qs.annotate(_debt=Coalesce( - SumSubquery(Debt.objects.filter(semester_id=get_ongoing_semester().pk, - student_id=OuterRef("pk")), 'debt'), - 0 - )) - qs = qs.annotate(_ongoing_semester_hours=Coalesce( - SumSubquery(Attendance.objects.filter( - training__group__semester_id=get_ongoing_semester().pk, student_id=OuterRef("pk")), 'hours'), - 0 - )) - qs = qs.annotate(complex_hours=ExpressionWrapper( - F('_ongoing_semester_hours') - F('_debt'), output_field=IntegerField() - )) - - return qs + # def get_queryset(self, request): + # qs = super().get_queryset(request) + # + # qs = qs.annotate(_debt=Coalesce( + # SumSubquery(Debt.objects.filter(semester_id=get_ongoing_semester().pk, + # student_id=OuterRef("pk")), 'debt'), + # 0 + # )) + # qs = qs.annotate(_ongoing_semester_hours=Coalesce( + # SumSubquery(Attendance.objects.filter( + # training__group__semester_id=get_ongoing_semester().pk, student_id=OuterRef("pk")), 'hours'), + # 0 + # )) + # qs = qs.annotate(complex_hours=ExpressionWrapper( + # F('_ongoing_semester_hours') - F('_debt'), output_field=IntegerField() + # )) + # + # return qs def get_hijack_user(self, obj): return obj.user diff --git a/adminpage/sport/models/student.py b/adminpage/sport/models/student.py index 2d6235e6..dc82a0c3 100644 --- a/adminpage/sport/models/student.py +++ b/adminpage/sport/models/student.py @@ -2,10 +2,14 @@ from django.core.mail import send_mail from django.db import models from django.core.exceptions import ValidationError +from django.db.models import OuterRef, ExpressionWrapper, F +from django.db.models.functions import Coalesce from django.db.models.signals import post_save from django.dispatch.dispatcher import receiver +from django.db.models import IntegerField from tinymce.models import HTMLField +# from api.crud import SumSubquery, get_ongoing_semester from sport.models import MedicalGroupHistory, Gender from sport.utils import get_current_study_year @@ -17,6 +21,37 @@ def validate_course(course): raise ValidationError('Course is bounded by 1 and 4') +class StudentManager(models.Manager): + + + def get_queryset(self): + from api.crud import get_ongoing_semester + from api.crud import SumSubquery + from sport.models import Attendance, Debt + + qs = super().get_queryset() + qs = qs.annotate(_debt=Coalesce( + SumSubquery(Debt.objects.filter( + semester_id=get_ongoing_semester().pk, + student_id=OuterRef("pk")), + 'debt', + ), + 0 + )) + qs = qs.annotate(_ongoing_semester_hours=Coalesce( + SumSubquery(Attendance.objects.filter( + training__group__semester_id=get_ongoing_semester().pk, + student_id=OuterRef("pk")), + 'hours', + ), + 0 + )) + qs = qs.annotate(hours=ExpressionWrapper( + F('_ongoing_semester_hours') - F('_debt'), output_field=IntegerField() + )) + + return qs + class Student(models.Model): user = models.OneToOneField( settings.AUTH_USER_MODEL, on_delete=models.CASCADE, @@ -78,6 +113,8 @@ class Student(models.Model): comment = HTMLField(null=True, blank=True, default='') + objects = StudentManager() + def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.__original_medical_group = self.medical_group From 698c129fe44dc3371a6eb3543b94fa01977b0a2b Mon Sep 17 00:00:00 2001 From: Danil Andreev Date: Sun, 5 Feb 2023 19:36:35 +0300 Subject: [PATCH 2/3] SPORT-636: Handle get_ongoing_semester exceptions --- adminpage/sport/models/student.py | 45 ++++++++++++++++--------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/adminpage/sport/models/student.py b/adminpage/sport/models/student.py index dc82a0c3..23232686 100644 --- a/adminpage/sport/models/student.py +++ b/adminpage/sport/models/student.py @@ -22,33 +22,36 @@ def validate_course(course): class StudentManager(models.Manager): - - def get_queryset(self): from api.crud import get_ongoing_semester from api.crud import SumSubquery from sport.models import Attendance, Debt + from django.db.utils import ProgrammingError qs = super().get_queryset() - qs = qs.annotate(_debt=Coalesce( - SumSubquery(Debt.objects.filter( - semester_id=get_ongoing_semester().pk, - student_id=OuterRef("pk")), - 'debt', - ), - 0 - )) - qs = qs.annotate(_ongoing_semester_hours=Coalesce( - SumSubquery(Attendance.objects.filter( - training__group__semester_id=get_ongoing_semester().pk, - student_id=OuterRef("pk")), - 'hours', - ), - 0 - )) - qs = qs.annotate(hours=ExpressionWrapper( - F('_ongoing_semester_hours') - F('_debt'), output_field=IntegerField() - )) + + try: + qs = qs.annotate(_debt=Coalesce( + SumSubquery(Debt.objects.filter( + semester_id=get_ongoing_semester().pk, + student_id=OuterRef("pk")), + 'debt', + ), + 0 + )) + qs = qs.annotate(_ongoing_semester_hours=Coalesce( + SumSubquery(Attendance.objects.filter( + training__group__semester_id=get_ongoing_semester().pk, + student_id=OuterRef("pk")), + 'hours', + ), + 0 + )) + qs = qs.annotate(hours=ExpressionWrapper( + F('_ongoing_semester_hours') - F('_debt'), output_field=IntegerField() + )) + except (ProgrammingError, IndexError): + pass return qs From 80f82e64434b138d3c227b3c29f34f51c09dd36a Mon Sep 17 00:00:00 2001 From: FleshRazer <61481131+FleshRazer@users.noreply.github.com> Date: Sun, 5 Feb 2023 22:25:24 +0300 Subject: [PATCH 3/3] Apply suggestions from code review Co-authored-by: Vladimir Makharev <43704968+kilimanj4r0@users.noreply.github.com> --- adminpage/sport/admin/studentAdmin.py | 18 ------------------ adminpage/sport/models/student.py | 1 - 2 files changed, 19 deletions(-) diff --git a/adminpage/sport/admin/studentAdmin.py b/adminpage/sport/admin/studentAdmin.py index 368a78ab..604c82da 100644 --- a/adminpage/sport/admin/studentAdmin.py +++ b/adminpage/sport/admin/studentAdmin.py @@ -278,24 +278,6 @@ def change_view(self, request, object_id, form_url='', extra_context=None): self.inlines = (ViewAttendanceInline,) return super().change_view(request, object_id, form_url, extra_context) - # def get_queryset(self, request): - # qs = super().get_queryset(request) - # - # qs = qs.annotate(_debt=Coalesce( - # SumSubquery(Debt.objects.filter(semester_id=get_ongoing_semester().pk, - # student_id=OuterRef("pk")), 'debt'), - # 0 - # )) - # qs = qs.annotate(_ongoing_semester_hours=Coalesce( - # SumSubquery(Attendance.objects.filter( - # training__group__semester_id=get_ongoing_semester().pk, student_id=OuterRef("pk")), 'hours'), - # 0 - # )) - # qs = qs.annotate(complex_hours=ExpressionWrapper( - # F('_ongoing_semester_hours') - F('_debt'), output_field=IntegerField() - # )) - # - # return qs def get_hijack_user(self, obj): return obj.user diff --git a/adminpage/sport/models/student.py b/adminpage/sport/models/student.py index 23232686..029da8ed 100644 --- a/adminpage/sport/models/student.py +++ b/adminpage/sport/models/student.py @@ -9,7 +9,6 @@ from django.db.models import IntegerField from tinymce.models import HTMLField -# from api.crud import SumSubquery, get_ongoing_semester from sport.models import MedicalGroupHistory, Gender from sport.utils import get_current_study_year