From bd5000a8b5e4203bf6805d5d8823c85de62a63cc Mon Sep 17 00:00:00 2001
From: dcz2 <dcz@ipipan.waw.pl>
Date: Mon, 11 Jul 2022 21:43:26 +0200
Subject: [PATCH] Performance optimization

---
 entries/views.py | 55 ++++++++++++++++++++++++++++++++++++++----------
 1 file changed, 44 insertions(+), 11 deletions(-)

diff --git a/entries/views.py b/entries/views.py
index d69fd47..8eb87d9 100644
--- a/entries/views.py
+++ b/entries/views.py
@@ -7,6 +7,7 @@ from itertools import chain, product
 
 import simplejson
 
+from django.contrib.auth.models import User
 from django.contrib.auth.decorators import login_required
 from django.db.models import Prefetch, Q
 from django.http import JsonResponse, QueryDict
@@ -24,6 +25,7 @@ from semantics.models import Frame, PredefinedSelectionalPreference, SelectivePr
 
 from common.decorators import ajax_required, ajax
 from unifier.models import UnifiedFrame
+from users.models import Assignment
 
 from .forms import (
     EntryForm,
@@ -372,9 +374,13 @@ def get_entries(request):
         
         linked_ids = set()
         if request.session['show_linked_entries']:
-            entries_linked = Entry.objects.filter(subentries__schema_hooks__argument_connections__schema_connections__subentry__entry__in=entries).distinct().exclude(id__in=entries)
+            entries_linked = Entry.objects.filter(pk__in=(
+                Entry.objects
+                .filter(subentries__schema_hooks__argument_connections__schema_connections__subentry__entry__in=entries)
+                .exclude(id__in=entries)
+            )).distinct()
             entries = entries | entries_linked
-            linked_ids = set(e.id for e in entries_linked)
+            linked_ids = set(entries_linked.values_list('id', flat=True))
         
         first_index, last_index = scroller_params['start'], scroller_params['start'] + scroller_params['length']
         order_field, order_dir = scroller_params['order']
@@ -386,12 +392,39 @@ def get_entries(request):
             order_field = 'pos__tag'
         if order_dir == 'desc':
             order_field = '-' + order_field
-        entries = entries.order_by(order_field).only('id', 'name', 'status__key', 'pos__tag')
+
+        if restrict_to_user:
+            # pre-filtering entries for performance reasons
+            entries = entries.filter(lexical_units__frames__assignments__user=User.objects.get(username=restrict_to_user))
+        entries = (
+            entries
+            .order_by(order_field)
+            .select_related('status', 'pos')
+            .prefetch_related(Prefetch("assignments", to_attr="_assignments"))
+        )
         if with_lexical_units:
-            entries = entries.prefetch_related("lexical_units")
+            entries = entries.prefetch_related(
+                Prefetch(
+                    "lexical_units",
+                    LexicalUnit.objects.prefetch_related(
+                        Prefetch(
+                            "frames",
+                            Frame.objects
+                            .select_related("slowal_frame_2_unified_frame")
+                            .prefetch_related(Prefetch("assignments", to_attr="_assignments")),
+                            to_attr="_frames",
+                        )
+                    )
+                )
+            )
         status_names = STATUS()
         POS_names = POS()
-        entriesList = list(entries)
+
+        def iter_lexical_units(e):
+            for lu in e.lexical_units.all():
+                lu._frame = lu._frames[0] if lu._frames else None
+                yield lu
+
         result = {
             'draw' : scroller_params['draw'],
             'recordsTotal': total,
@@ -403,7 +436,7 @@ def get_entries(request):
                     'status'  : status_names[e.status.key],
                     'POS'     : POS_names[e.pos.tag],
                     'related' : e.id in linked_ids,
-                    'assignee_username': assignment.user.username if (assignment := e.assignments.first()) else None,
+                    'assignee_username': e._assignments[0].user.username if e._assignments else None,
                     **(
                         {
                             'lexical_units': [
@@ -411,16 +444,16 @@ def get_entries(request):
                                     'pk': lu.pk,
                                     'display': str(lu),
                                     'assignee_username': (
-                                        assignment.user.username if (frame := lu.frames.first()) and (assignment := frame.assignments.first()) else None
+                                        lu._frame._assignments[0].user.username if lu._frame and lu._frame._assignments else None
                                     ),
-                                    'status': frame.status if (frame := lu.frames.first()) else "",
-                                    'unified_frame_id': frame.slowal_frame_2_unified_frame.unified_frame_id if (frame := lu.frames.first()) and hasattr(frame, 'slowal_frame_2_unified_frame') else -1,
-                                } for lu in e.lexical_units.all()
+                                    'status': lu._frame.status if lu._frame else "",
+                                    'unified_frame_id': lu._frame.slowal_frame_2_unified_frame.unified_frame_id if lu._frame and hasattr(lu._frame, 'slowal_frame_2_unified_frame') else -1,
+                                } for lu in iter_lexical_units(e)
                             ]
                         }
                         if with_lexical_units else {}
                     ),
-                } for e in entriesList[first_index:last_index]
+                } for e in entries[first_index:last_index]
             ],
         }
 
-- 
GitLab