From 96c789014f682eb9bd8eef98d1fe59ca03516e1b Mon Sep 17 00:00:00 2001
From: mirabilos <thorsten.glaser@teckids.org>
Date: Tue, 3 Sep 2019 23:32:26 +0200
Subject: [PATCH] =?UTF-8?q?Use=20an=20SQL=20=E2=80=9CWHERE=20NOT=20EXISTS?=
 =?UTF-8?q?=E2=80=9D=20subclause.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This is correct performance-wise (avoids the need for the database to
build the entire result set before filtering; Django users reported a
speed-up of factor 5‥2000 over naïve solutions) and (accepted by Nik)
even more legible.
---
 biscuit/apps/alsijil/views.py | 18 +++++++++++-------
 1 file changed, 11 insertions(+), 7 deletions(-)

diff --git a/biscuit/apps/alsijil/views.py b/biscuit/apps/alsijil/views.py
index 69e10cdcd..57d1ab82b 100644
--- a/biscuit/apps/alsijil/views.py
+++ b/biscuit/apps/alsijil/views.py
@@ -2,7 +2,7 @@ from collections import OrderedDict
 from typing import Optional
 
 from django.contrib.auth.decorators import login_required
-from django.db.models import Q
+from django.db.models import Exists, OuterRef, Q
 from django.http import HttpRequest, HttpResponse
 from django.shortcuts import render
 from django.views.decorators.cache import cache_page
@@ -41,13 +41,17 @@ def lesson(request: HttpRequest, week: Optional[int] = None, period_id: Optional
             request.POST or None, instance=lesson_documentation, prefix='leson_documentation')
 
         # Create all missing personal notes about members of all groups in lesson
-        missing_persons = Person.objects.filter(
+        missing_persons = Person.objects.annotate(
+            no_personal_notes=~Exists(PersonalNote.objects.filter(
+                week=wanted_week,
+                lesson_period=lesson_period,
+                person__pk=OuterRef('pk')
+            ))
+        ).filter(
             member_of__in=Group.objects.filter(pk__in=lesson_period.lesson.groups.all()),
-            is_active=True
-        ).exclude(
-            personal_notes__week=wanted_week,
-            personal_notes__lesson_period=lesson_period
-        ).all()
+            is_active=True,
+            no_personal_notes=True
+        )
         PersonalNote.objects.bulk_create([
             PersonalNote(person=person, lesson_period=lesson_period,
                          week=wanted_wek) for person in missing_persons
-- 
GitLab