From 0aceecf04cf720525772a9801d7799f19e5a3cd1 Mon Sep 17 00:00:00 2001 From: Alban Gruin Date: Sat, 27 Jan 2018 21:59:42 +0100 Subject: Remplacement de la requête de QSJPS par une autre, plus simple et plus rapide à exécuter sur de gros volumes de données. On aura peut-être besoin d’utiliser un double index pour augmenter encore plus les performances. La requête liste tous les cours commençant avant la fin de l’intervalle et finissant après le début de l’intervalle, en excluant les cours n’ayant pas de salle assignée. On récupère ensuite la liste des salles de ces cours, et on inverse le contenu de la liste. On trie ensuite les cours par leur nom. --- models.py | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/models.py b/models.py index e907944..8ff9359 100644 --- a/models.py +++ b/models.py @@ -16,7 +16,7 @@ from functools import reduce from django.db import models -from django.db.models import Manager, OuterRef, Q, Subquery, Value +from django.db.models import Manager, Q from django.db.models.functions import ExtractWeek, ExtractYear from django.utils import timezone from django.utils.text import slugify @@ -162,26 +162,19 @@ class Group(SlugModel): class RoomManager(Manager): def qsjps(self, begin, end): - # On compte tous les cours correspondant à chaque salle - # commençant avant la fin de l’intervalle et finissant après - # le début de l’intervalle. Ces cours se trouvent à un moment - # dans l’intervalle, et la salle assignée à ce cours ne peut - # donc pas être sélectionnée. Pour accélérer la requête, on - # s’arrête au premier cours trouvé. + # On récupère la liste des cours qui commencent avant la fin + # de l’intervalle sélectionné et qui terminent après le début + # de l’intervalle, c’est-à-dire qu’au moins une partie du + # cours se déroule pendant l’intervalle. On récupère ensuite + # la liste des salles dans lesquelles se déroulent ces + # cours. On exclu les cours n’ayant aucune salle assignée. courses = Course.objects.filter(begin__lt=end, end__gt=begin, - rooms=OuterRef("pk")) \ - .annotate(c=Value(1, - output_field=models.IntegerField())) \ - .values_list("c", flat=True)[:1] - - # On sélectionne toutes les salles qui n’ont aucun de cours se - # trouvant au moins en partie dans l’intervalle entré par - # l’utilisateur. - rooms = self.get_queryset().annotate( - c=Subquery(courses, output_field=models.IntegerField())) \ - .filter(c__isnull=True).order_by("name") - - return rooms + rooms__isnull=False) \ + .values_list("rooms", flat=True) + + # On sélectionne ensuite les salles qui ne sont pas dans la + # liste récupérée plus haut, et on les trie par leur nom. + return self.get_queryset().exclude(pk__in=courses).order_by("name") class Room(SlugModel): -- cgit v1.2.1