performed some stupid ass shit nested many to many count to fix broken ass numbers

This commit is contained in:
Valentin Moguérou 2024-05-05 07:46:23 +02:00
parent 3d58b9aa0e
commit 87b31dba62
2 changed files with 44 additions and 24 deletions

View File

@ -1,11 +1,12 @@
from datetime import date, datetime, timedelta from datetime import date, datetime, timedelta
from pprint import pprint
from pytz import timezone from pytz import timezone
import aiohttp import aiohttp
from django.db import models from django.db import models
from django.db.models import F, Q, Count, QuerySet from django.db.models import F, Q, Count, QuerySet, Subquery, OuterRef, Sum
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.conf import settings from django.conf import settings
@ -144,25 +145,35 @@ class Term(models.Model):
.select_related("slot", "slot__term") .select_related("slot", "slot__term")
.prefetch_related("swap_set") .prefetch_related("swap_set")
.filter(slot__term=self) .filter(slot__term=self)
.annotate(adt_plus=Count("swap", filter=Q(swap__enroll=1))) .annotate(base_vol=Count("groups__members"))
.annotate(adt_minus=Count("swap", filter=Q(swap__enroll=0))) .annotate(swap_plus=Count("swap", filter=Q(swap__enroll=1), distinct=True))
.annotate(volume=F("slot__capacity") + F("adt_plus") - F("adt_minus"))) .annotate(swap_minus=Count("swap", filter=Q(swap__enroll=0), distinct=True))
.annotate(volume=F("base_vol") + F("swap_plus") - F("swap_minus")))
def query_colles_of_student(self, student) -> QuerySet: def query_colles_of_student(self, student) -> QuerySet:
has_student = ((Q(groups__student=student)
& ~Q(swap__enroll=0, swap__student=student))
| Q(swap__enroll=1, swap__student=student))
return (Colle.objects return (Colle.objects
.select_related("slot", "slot__term") .select_related("slot", "slot__term")
.prefetch_related("swap_set") .prefetch_related("swap_set")
.filter(slot__term=self) .filter(slot__term=self)
.filter((Q(groups__student=student) .annotate(base_vol=Count("groups__members", distinct=True))
& ~Q(swap__enroll=0, swap__student=student)) .annotate(swap_plus=Count("pk", filter=Q(swap__enroll=1), distinct=True))
| Q(swap__enroll=1, swap__student=student)) .annotate(swap_minus=Count("pk", filter=Q(swap__enroll=0), distinct=True))
.annotate(adt_plus=Count("swap", filter=Q(swap__enroll=1))) .annotate(volume=F("base_vol") + F("swap_plus") - F("swap_minus"))
.annotate(adt_minus=Count("swap", filter=Q(swap__enroll=0))) .filter(has_student)
.annotate(volume=F("slot__capacity") + F("adt_plus") - F("adt_minus"))) )
def query_colles_not_full_excluding_student(self, student) -> QuerySet:
has_student = ((Q(groups__student=student)
& ~Q(swap__enroll=0, swap__student=student))
| Q(swap__enroll=1, swap__student=student))
def query_colles_not_full(self) -> QuerySet:
return (self.query_colles() return (self.query_colles()
.filter(volume__lt=F("slot__capacity"), date__gte=date.today())) .filter(volume__lt=F("slot__capacity"), date__gte=date.today())
.exclude(has_student))
def __str__(self) -> str: def __str__(self) -> str:
return self.description return self.description
@ -295,7 +306,7 @@ class Colle(models.Model):
"slot__time"] "slot__time"]
slot = models.ForeignKey(Slot, on_delete=models.CASCADE) slot = models.ForeignKey(Slot, on_delete=models.CASCADE)
groups = models.ManyToManyField(Group) groups = models.ManyToManyField(Group, blank=True)
date = models.DateField() date = models.DateField()
def initial_group(self): def initial_group(self):
@ -319,23 +330,22 @@ class Colle(models.Model):
def is_attendee(self, student): def is_attendee(self, student):
return self.final_group().contains(student) return self.final_group().contains(student)
def get_volume(self):
def volume(self):
""" """
Renvoie le nombre d'étudiants inscrits à la colle en tenant compte des swaps. Renvoie le nombre d'étudiants inscrits à la colle en tenant compte des swaps.
""" """
n_base = sum(group.members.count() for group in self.groups.all()) return (Student.objects
n_plus = len(Swap.objects.filter(enroll=True, colle=self)) .filter(Q(groups__colle=self)
n_moins = len(Swap.objects.filter(enroll=False, colle=self)) & ~Q(swap__colle=self, swap__enroll=False)
| Q(swap__colle=self, swap__enroll=True))
return n_base + n_plus - n_moins .distinct()
.count())
def is_full(self): def is_full(self):
""" """
Renvoie si la colle est pleine. Renvoie si la colle est pleine.
""" """
eff = self.volume() return self.get_volume() >= self.slot.capacity
return eff >= self.slot.capacity
def is_edited(self): def is_edited(self):
""" """
@ -369,7 +379,7 @@ class Colle(models.Model):
# func() # func()
def __str__(self): def __str__(self):
return f"{self.slot} le {self.date} avec groupes {'+'.join(str(groupe) for groupe in self.groups.all())}" return f"Colle {self.slot.subject} ({self.slot.colleur}); {self.date} {self.slot.time} {self.slot.room}. Groupe(s) {{{'; '.join(str(groupe) for groupe in self.groups.all())}}}"
def datetime(self): def datetime(self):
return datetime.combine(self.date, self.slot.time, tzinfo=timezone("Europe/Paris")) return datetime.combine(self.date, self.slot.time, tzinfo=timezone("Europe/Paris"))
@ -425,3 +435,13 @@ class CalendarLink(models.Model):
fields=['student', 'term'], name='unique_student_term_combination' fields=['student', 'term'], name='unique_student_term_combination'
) )
] ]
def test():
valentin = Student.objects.get(pk=25)
term = Term.objects.get(pk=3)
colles = term.query_colles_of_student(valentin).order_by("-volume")
for c in colles:
print(f"* {c.slot} {c.volume} : {c.base_vol} + {c.swap_plus} - {c.swap_minus}")

View File

@ -131,7 +131,7 @@ def marketplace(request):
return HttpResponse("pas encore supporté") return HttpResponse("pas encore supporté")
term = student.cls.current_term() term = student.cls.current_term()
colles = term.query_colles_not_full() colles = term.query_colles_not_full_excluding_student(student)
context = { context = {
"colles": colles, "colles": colles,