From bd5e9e2b6e85991d80c992191ec1eb23fdc15c3f Mon Sep 17 00:00:00 2001 From: Chris Church Date: Thu, 8 Aug 2013 17:44:48 -0400 Subject: [PATCH] For AC-331. Update queries to use select_related and prefetch_related to avoid duplicate queries and improve performance. Add all_groups and groups items to summary_fields for hosts. --- awx/main/access.py | 19 +++++++++++++++++++ awx/main/base_views.py | 6 +++--- awx/main/serializers.py | 11 +++++++++-- 3 files changed, 31 insertions(+), 5 deletions(-) diff --git a/awx/main/access.py b/awx/main/access.py index 88bf3dd4af..2ad3c77bc7 100644 --- a/awx/main/access.py +++ b/awx/main/access.py @@ -217,6 +217,7 @@ class OrganizationAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.distinct() + qs = qs.select_related('created_by') if self.user.is_superuser: return qs return qs.filter(Q(admins__in=[self.user]) | Q(users__in=[self.user])) @@ -249,6 +250,7 @@ class InventoryAccess(BaseAccess): def get_queryset(self, allowed=None): allowed = allowed or PERMISSION_TYPES_ALLOWING_INVENTORY_READ qs = Inventory.objects.filter(active=True).distinct() + qs = qs.select_related('created_by', 'organization') if self.user.is_superuser: return qs admin_of = qs.filter(organization__admins__in=[self.user]).distinct() @@ -318,6 +320,9 @@ class HostAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.filter(active=True).distinct() + qs = qs.select_related('created_by', 'inventory', 'last_job', + 'last_job_host_summary') + qs = qs.prefetch_related('groups') inventories_qs = self.user.get_queryset(Inventory) return qs.filter(inventory__in=inventories_qs) @@ -378,6 +383,8 @@ class GroupAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.filter(active=True).distinct() + qs = qs.select_related('created_by', 'inventory') + qs = qs.prefetch_related('parents', 'children') inventories_qs = self.user.get_queryset(Inventory) return qs.filter(inventory__in=inventories_qs) @@ -440,6 +447,7 @@ class CredentialAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.filter(active=True).distinct() + qs = qs.select_related('created_by', 'user', 'team') if self.user.is_superuser: return qs orgs_as_admin = self.user.admin_of_organizations.all() @@ -509,6 +517,7 @@ class TeamAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.filter(active=True).distinct() + qs = qs.select_related('created_by', 'organization') if self.user.is_superuser: return qs return qs.filter( @@ -560,6 +569,7 @@ class ProjectAccess(BaseAccess): def get_queryset(self): qs = Project.objects.filter(active=True).distinct() + qs = qs.select_related('created_by') if self.user.is_superuser: return qs allowed = [PERM_INVENTORY_DEPLOY, PERM_INVENTORY_CHECK] @@ -609,6 +619,8 @@ class PermissionAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.filter(active=True).distinct() + qs = qs.select_related('created_by', 'user', 'team', 'inventory', + 'project') if self.user.is_superuser: return qs orgs_as_admin = self.user.admin_of_organizations.all() @@ -699,6 +711,8 @@ class JobTemplateAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.filter(active=True).distinct() + qs = qs.select_related('created_by', 'inventory', 'project', + 'credential') if self.user.is_superuser: return qs credential_qs = self.user.get_queryset(Credential) @@ -801,6 +815,8 @@ class JobAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.filter(active=True).distinct() + qs = qs.select_related('created_by', 'job_template', 'inventory', + 'project', 'credential') if self.user.is_superuser: return qs credential_qs = self.user.get_queryset(Credential) @@ -870,6 +886,7 @@ class JobHostSummaryAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.distinct() + qs = qs.select_related('created_by', 'job', 'host') if self.user.is_superuser: return qs job_qs = self.user.get_queryset(Job) @@ -894,6 +911,8 @@ class JobEventAccess(BaseAccess): def get_queryset(self): qs = self.model.objects.distinct() + qs = qs.select_related('created_by', 'job', 'host', 'parent') + qs = qs.prefetch_related('hosts', 'children') # Filter certain "internal" events generating by async polling. qs = qs.exclude(event__in=('runner_on_ok', 'runner_on_failed'), diff --git a/awx/main/base_views.py b/awx/main/base_views.py index d3ad2c03c8..4c67ce051c 100644 --- a/awx/main/base_views.py +++ b/awx/main/base_views.py @@ -51,6 +51,9 @@ class GenericAPIView(generics.GenericAPIView, APIView): # model = ModelClass # serializer_class = SerializerClass + def get_queryset(self): + return self.request.user.get_queryset(self.model) + def get_description_context(self): # Set instance attributes needed to get serializer metadata. if not hasattr(self, 'request'): @@ -80,9 +83,6 @@ class ListAPIView(generics.ListAPIView, GenericAPIView): }) return d - def get_queryset(self): - return self.request.user.get_queryset(self.model) - class ListCreateAPIView(ListAPIView, generics.ListCreateAPIView): # Base class for a list view that allows creating new objects. diff --git a/awx/main/serializers.py b/awx/main/serializers.py index 35ffa17957..af05643dea 100644 --- a/awx/main/serializers.py +++ b/awx/main/serializers.py @@ -27,7 +27,7 @@ BASE_FIELDS = ('id', 'url', 'related', 'summary_fields', 'created', 'name', # objects that if found we should add summary info for them SUMMARIZABLE_FKS = ( 'organization', 'host', 'group', 'inventory', 'project', 'team', 'job', - 'job_template', 'credential', 'permission', 'user', + 'job_template', 'credential', 'permission', 'user', 'last_job', ) # fields that should be summarized regardless of object type SUMMARIZABLE_FIELDS = ( @@ -244,7 +244,8 @@ class HostSerializer(BaseSerializerWithVariables): class Meta: model = Host - fields = BASE_FIELDS + ('inventory', 'variables', 'has_active_failures') + fields = BASE_FIELDS + ('inventory', 'variables', 'has_active_failures', + 'last_job', 'last_job_host_summary') def get_related(self, obj): res = super(HostSerializer, self).get_related(obj) @@ -262,6 +263,12 @@ class HostSerializer(BaseSerializerWithVariables): res['last_job_host_summary'] = reverse('main:job_host_summary_detail', args=(obj.last_job_host_summary.pk,)) return res + def get_summary_fields(self, obj): + d = super(HostSerializer, self).get_summary_fields(obj) + d['all_groups'] = [{'id': g.id, 'name': g.name} for g in obj.all_groups.all()] + d['groups'] = [{'id': g.id, 'name': g.name} for g in obj.groups.all()] + return d + class GroupSerializer(BaseSerializerWithVariables): class Meta: