Repository: hydroshare/hydroshare

Issue:
Group listing performance improvements
Currently it takes about 10 secs to list 130 groups. As more groups are added, the page load time will get worse. It seems there are opportunities to minimize number of queries needed for listing groups and hence improve page load time.  


Discussion:

Resolving patch:
diff --git a/hs_access_control/models/group.py b/hs_access_control/models/group.py
--- a/hs_access_control/models/group.py
+++ b/hs_access_control/models/group.py
@@ -102,7 +102,7 @@ def owners(self):
 
         return User.objects.filter(is_active=True,
                                    u2ugp__group=self.group,
-                                   u2ugp__privilege=PrivilegeCodes.OWNER)
+                                   u2ugp__privilege=PrivilegeCodes.OWNER).select_related('userprofile')
 
     @property
     def __edit_users_of_group(self):
@@ -158,7 +158,7 @@ def members(self):
         """
         return User.objects.filter(is_active=True,
                                    u2ugp__group=self.group,
-                                   u2ugp__privilege__lte=PrivilegeCodes.VIEW)
+                                   u2ugp__privilege__lte=PrivilegeCodes.VIEW).select_related('userprofile')
 
     @property
     def viewers(self):
@@ -216,7 +216,7 @@ def view_resources(self):
         :return: QuerySet of resource objects held by group.
 
         """
-        return BaseResource.objects.filter(self.__view_resources_of_group)
+        return BaseResource.objects.filter(self.__view_resources_of_group).select_related('raccess')
 
     @property
     def edit_resources(self):
diff --git a/hs_access_control/models/user.py b/hs_access_control/models/user.py
--- a/hs_access_control/models/user.py
+++ b/hs_access_control/models/user.py
@@ -394,7 +394,7 @@ def my_groups(self):
                                       gaccess__active=True) |
                                     Q(g2ugp__user=self.user,
                                       gaccess__active=False,
-                                      g2ugp__privilege=PrivilegeCodes.OWNER))\
+                                      g2ugp__privilege=PrivilegeCodes.OWNER)).select_related('gaccess')\
                             .distinct()
 
     #################################
diff --git a/hs_core/views/__init__.py b/hs_core/views/__init__.py
--- a/hs_core/views/__init__.py
+++ b/hs_core/views/__init__.py
@@ -1831,17 +1831,24 @@ def get_context_data(self, **kwargs):
         if self.request.user.is_authenticated():
             u = User.objects.get(pk=self.request.user.id)
 
-            groups = Group.objects.filter(gaccess__active=True).exclude(name="Hydroshare Author")
+            groups = Group.objects.filter(gaccess__active=True).exclude(
+                name="Hydroshare Author").select_related('gaccess')
             for g in groups:
-                g.is_user_member = u in g.gaccess.members
-                g.join_request_waiting_owner_action = g.gaccess.group_membership_requests.filter(
-                    request_from=u).exists()
-                g.join_request_waiting_user_action = g.gaccess.group_membership_requests.filter(
-                    invitation_to=u).exists()
+                g.members = g.gaccess.members
+                g.is_user_member = u in g.members
                 g.join_request = None
-                if g.join_request_waiting_owner_action or g.join_request_waiting_user_action:
-                    g.join_request = g.gaccess.group_membership_requests.filter(request_from=u).first() or \
-                                     g.gaccess.group_membership_requests.filter(invitation_to=u).first()
+                if g.is_user_member:
+                    g.join_request_waiting_owner_action = False
+                    g.join_request_waiting_user_action = False
+                else:
+                    g.join_request_waiting_owner_action = g.gaccess.group_membership_requests.filter(
+                        request_from=u).exists()
+                    g.join_request_waiting_user_action = g.gaccess.group_membership_requests.filter(
+                        invitation_to=u).exists()
+
+                    if g.join_request_waiting_owner_action or g.join_request_waiting_user_action:
+                        g.join_request = g.gaccess.group_membership_requests.filter(request_from=u).first() or \
+                                         g.gaccess.group_membership_requests.filter(invitation_to=u).first()
             return {
                 'profile_user': u,
                 'groups': groups
@@ -1852,6 +1859,8 @@ def get_context_data(self, **kwargs):
                                           (Q(gaccess__discoverable=True) |
                                           Q(gaccess__public=True))).exclude(name="Hydroshare Author")
 
+            for g in groups:
+                g.members = g.gaccess.members
             return {
                 'groups': groups
             }
@@ -1915,11 +1924,12 @@ def get_context_data(self, **kwargs):
         group_resources = sorted(group_resources, key=lambda x: x.date_granted, reverse=True)
 
         if self.request.user.is_authenticated():
+            group_members = g.gaccess.members
             u = User.objects.get(pk=self.request.user.id)
             u.is_group_owner = u.uaccess.owns_group(g)
             u.is_group_editor = g in u.uaccess.edit_groups
             u.is_group_viewer = g in u.uaccess.view_groups or g.gaccess.public or g.gaccess.discoverable
-            u.is_group_member = u in g.gaccess.members
+            u.is_group_member = u in group_members
 
             g.join_request_waiting_owner_action = g.gaccess.group_membership_requests.filter(request_from=u).exists()
             g.join_request_waiting_user_action = g.gaccess.group_membership_requests.filter(invitation_to=u).exists()
@@ -1932,7 +1942,7 @@ def get_context_data(self, **kwargs):
                 Q(invitation_to=None) | Q(invitation_to__is_active=True)
             )
 
-            if u not in g.gaccess.members:
+            if u not in group_members:
                 group_resources = [r for r in group_resources if r.raccess.public or r.raccess.discoverable]
 
             return {


Test patch: