Repository: akvo/akvo-rsr

Issue:
User management page slow
Probably due to a change in #1398, the user management page takes a lot longer to load.



Discussion:

Resolving patch:
diff --git a/akvo/rsr/models/user.py b/akvo/rsr/models/user.py
--- a/akvo/rsr/models/user.py
+++ b/akvo/rsr/models/user.py
@@ -7,7 +7,6 @@
 from django.contrib.auth.models import AbstractBaseUser, BaseUserManager, PermissionsMixin, Group
 from django.core.mail import send_mail
 from django.db import models
-from django.db.models.query import QuerySet
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
 
@@ -52,9 +51,6 @@ def create_user(self, username, email, password=None, **extra_fields):
     def create_superuser(self, username, email, password, **extra_fields):
         return self._create_user(username, email, password, True, True, **extra_fields)
 
-    def get_queryset(self):
-        return self.model.QuerySet(self.model)
-
     def __getattr__(self, attr, *args):
         try:
             return getattr(self.__class__, attr, *args)
@@ -113,14 +109,6 @@ class Meta:
         verbose_name_plural = _(u'users')
         ordering = ['username', ]
 
-    class QuerySet(QuerySet):
-        def have_employments(self):
-            qs = self
-            for user in qs:
-                if not user.employers.all():
-                    qs = qs.exclude(pk=user.pk)
-            return qs
-
     def __unicode__(self):
         return self.username
 
diff --git a/akvo/rsr/permissions.py b/akvo/rsr/permissions.py
--- a/akvo/rsr/permissions.py
+++ b/akvo/rsr/permissions.py
@@ -72,6 +72,8 @@ def is_org_user_manager(user, obj):
                 return True
             elif type(obj) == Project and obj in employment.organisation.all_projects():
                 return True
+            elif type(obj) == Organisation and obj == employment.organisation:
+                return True
     return False
 
 @rules.predicate
diff --git a/akvo/rsr/views/my_rsr.py b/akvo/rsr/views/my_rsr.py
--- a/akvo/rsr/views/my_rsr.py
+++ b/akvo/rsr/views/my_rsr.py
@@ -9,10 +9,11 @@
 
 import json
 
-from django.contrib.auth import get_user_model
 from django.contrib.auth.decorators import login_required
+from django.contrib.auth.models import Group
 from django.core.exceptions import PermissionDenied
 from django.core.urlresolvers import reverse
+from django.forms.models import model_to_dict
 from django.http import HttpResponseRedirect
 from django.shortcuts import render, render_to_response
 from django.template import RequestContext
@@ -21,7 +22,7 @@
                      SelectOrgForm, IatiExportForm)
 from ..filters import remove_empty_querydict_items
 from ...utils import pagination, filter_query_string
-from ..models import Country, Organisation
+from ..models import Country, Organisation, Employment
 
 
 @login_required
@@ -184,31 +185,61 @@ def user_management(request):
         raise PermissionDenied
 
     if user.is_support and user.is_admin:
-        users = get_user_model().objects.filter(is_active=True)\
-            .order_by('-date_joined').have_employments()
-        org_actions = Organisation.objects.all()
+        employments = Employment.objects.select_related().\
+            prefetch_related('country', 'group').order_by('-id')
     else:
         organisations = user.employers.approved().organisations()
-        users = organisations.users().exclude(pk=user.pk)\
-            .order_by('-date_joined').have_employments()
-        org_actions = [org for org in organisations if user.has_perm('rsr.user_management', org)]
+        for org in organisations:
+            if not user.has_perm('rsr.user_management', org):
+                organisations = organisations.exclude(pk=org.pk)
+        employments = organisations.employments().exclude(user=user).select_related().\
+            prefetch_related('country', 'group').order_by('-id')
 
     q = request.GET.get('q')
     if q:
         q_list = q.split()
         for q_item in q_list:
-            users = users.filter(username__icontains=q_item) | \
-                users.filter(first_name__icontains=q_item) | \
-                users.filter(last_name__icontains=q_item)
+            employments = employments.filter(user__username__icontains=q_item) | \
+                employments.filter(user__first_name__icontains=q_item) | \
+                employments.filter(user__last_name__icontains=q_item)
 
     page = request.GET.get('page')
-    page, paginator, page_range = pagination(page, users, 10)
-
-    users_array = [u.employments_dict(org_actions) for u in page]
+    page, paginator, page_range = pagination(page, employments, 10)
+
+    all_groups = [
+        Group.objects.get(name='Users'),
+        Group.objects.get(name='User Managers'),
+        Group.objects.get(name='Project Editors'),
+        Group.objects.get(name='Admins')
+    ]
+
+    employments_array = []
+    for employment in page:
+        employment_dict = model_to_dict(employment)
+        employment_dict['other_groups'] = [
+            model_to_dict(group, fields=['id', 'name']) for group in all_groups
+        ]
+        if employment.country:
+            country_dict = model_to_dict(employment.country, fields=['id', 'iso_code', 'name'])
+            employment_dict["country"] = country_dict
+        if employment.group:
+            group_dict = model_to_dict(employment.group, fields=['id', 'name'])
+            employment_dict["group"] = group_dict
+        if employment.organisation:
+            organisation_dict = model_to_dict(employment.organisation, fields=[
+                'id', 'name', 'long_name'
+            ])
+            employment_dict["organisation"] = organisation_dict
+        if employment.user:
+            user_dict = model_to_dict(employment.user, fields=[
+                'id', 'first_name', 'last_name', 'email'
+            ])
+            employment_dict["user"] = user_dict
+        employments_array.append(employment_dict)
 
     context = {}
-    if users_array:
-        context['user_data'] = json.dumps({'users': users_array, })
+    if employments_array:
+        context['employments'] = json.dumps(employments_array)
     context['page'] = page
     context['paginator'] = paginator
     context['page_range'] = page_range


Test patch: