Projet

Général

Profil

Development #43306

Réduire le nombre de queryset sur les pages day/month d'un calendrier

Ajouté par Lauréline Guérin il y a presque 4 ans. Mis à jour il y a presque 4 ans.

Statut:
Fermé
Priorité:
Normal
Assigné à:
Catégorie:
-
Version cible:
-
Début:
26 mai 2020
Echéance:
% réalisé:

0%

Temps estimé:
Patch proposed:
Oui
Planning:
Non

Description

Ajouter quelques prefetch bien placés


Fichiers

Révisions associées

Révision 06ee841b (diff)
Ajouté par Lauréline Guérin il y a presque 4 ans

agendas: add tests on queryset for day/month views (#43306)

Révision 1119909e (diff)
Ajouté par Lauréline Guérin il y a presque 4 ans

agendas: reduce querysets on day/month views (#43306)

Historique

#1

Mis à jour par Lauréline Guérin il y a presque 4 ans

    def get_opening_hours(self, date):
        if hasattr(self, 'prefetched_timeperiods'):
            timeperiods = self.prefetched_timeperiods
        else:
            timeperiods = self.timeperiod_set.all()

        openslots = IntervalSet()
        for timeperiod in timeperiods:
            if timeperiod.weekday != date.weekday():
                continue
            start_datetime = make_aware(datetime.datetime.combine(date, timeperiod.start_time))
            end_datetime = make_aware(datetime.datetime.combine(date, timeperiod.end_time))
            openslots.add(start_datetime, end_datetime)

        if hasattr(self, 'prefetched_exceptions'):
            timeexceptions = self.prefetched_exceptions
        else:
            timeexceptions = self.timeperiodexception_set.all()

        aware_date = make_aware(datetime.datetime(date.year, date.month, date.day))
        exceptions = IntervalSet()
        aware_next_date = aware_date + datetime.timedelta(days=1)
        for exception in timeexceptions:
            if exception.end_datetime < aware_date:
                continue
            if exception.start_datetime > aware_next_date:
                continue
            exceptions.add(exception.start_datetime, exception.end_datetime)

        return [OpeningHour(*time_range) for time_range in (openslots - exceptions)]

J'ai utilisé des prefetch pour les time periods et les exceptions, quitte à devoir filtrer à la main plutôt que passer par un queryset filtrant:
sur la vue month, on appelle cette méthode pour chaque jour affiché, ce qui fait autant de querysets.
(les exceptions étaient déjà prefetch dans la vue, autant les réutiliser dans la méthode get_opening_hours)

#2

Mis à jour par Benjamin Dauvergne il y a presque 4 ans

Il me semble1 que passer par self.prefetched_truc est inutile, si tu prefetch une propriété truc_set alors instance.truc_set.all() utilise la valeur préfetchée (et uniquement via .all() si tu filtres par n'importe quoi d'autre ça n'utilise plus la valeur préfetchée, ça refait une requête).

Donc tu dois pouvoir simplifier les choses ainsi

-      .prefetch_related(Prefetch('timeperiod_set', to_attr='prefetched_timeperiods'))
+      .prefetch_related('timeperiod_set')
....
-        if hasattr(self, 'prefetched_timeperiods'):
-            timeperiods = self.prefetched_timeperiods
-        else:
-            timeperiods = self.timeperiod_set.all()
+        timeperiods = self.timeperiod_set.all()

1 https://docs.djangoproject.com/fr/3.0/ref/models/querysets/#django.db.models.query.QuerySet.prefetch_related

#3

Mis à jour par Benjamin Dauvergne il y a presque 4 ans

  • Statut changé de Solution proposée à En cours
#4

Mis à jour par Lauréline Guérin il y a presque 4 ans

Je sais bien, mais j'aime bien en général poser mes prefetch dans un to_attr: c'est plus explicite, à la lecture du code on sait de suite d'où ça vient.
Je voulais éviter qu'on soit dans le futur tentés de remettre un queryset filtré dans la méthode get_opening_hours: si on voit que c'est prefetché alors on sait qu'on ne doit pas y toucher sans y avoir mûrement réfléchi.
Mais, ça se tient, sans to_attr on peut reduire un peu le code :) Du coup j'ai posé des commentaires.

#6

Mis à jour par Benjamin Dauvergne il y a presque 4 ans

  • Statut changé de Solution proposée à Solution validée

Lauréline Guerin a écrit :

Je voulais éviter qu'on soit dans le futur tentés de remettre un queryset filtré dans la méthode

get_opening_hours: si on voit que c'est prefetché alors on sait qu'on ne doit pas y toucher sans y avoir mûrement réfléchi.

Les tests sur le nombre de query évite facilement ce genre d'accident.

#7

Mis à jour par Lauréline Guérin il y a presque 4 ans

  • Statut changé de Solution validée à Résolu (à déployer)
commit 1119909e34a94a1adeb282ad3757f34ba21e16e7
Author: Lauréline Guérin <zebuline@entrouvert.com>
Date:   Mon May 25 14:52:08 2020 +0200

    agendas: reduce querysets on day/month views (#43306)

commit 06ee841b111cbc9f5819091f3d518605dd5b0513
Author: Lauréline Guérin <zebuline@entrouvert.com>
Date:   Mon May 25 14:47:11 2020 +0200

    agendas: add tests on queryset for day/month views (#43306)
#8

Mis à jour par Frédéric Péters il y a presque 4 ans

  • Statut changé de Résolu (à déployer) à Solution déployée

Formats disponibles : Atom PDF