From 3bdb6362ad28dd67aa61a93cd0d283fc8db6ed7b Mon Sep 17 00:00:00 2001 From: Dirk Julich Date: Thu, 18 Jun 2026 15:19:09 +0200 Subject: [PATCH] Handle missing Organization Member/Admin role definitions gracefully Use filter().first() instead of get() for RoleDefinition lookups in organization list and detail views. Returns 0 for user/admin counts when role definitions are not yet created, preventing 500 errors in environments where post_migrate signals haven't run. Co-Authored-By: Claude Opus 4.6 --- awx/api/views/mixin.py | 40 +++++++++++++------------ awx/api/views/organization.py | 55 +++++++++++++++++++---------------- 2 files changed, 51 insertions(+), 44 deletions(-) diff --git a/awx/api/views/mixin.py b/awx/api/views/mixin.py index 686d4d0ace..e804fc0ff6 100644 --- a/awx/api/views/mixin.py +++ b/awx/api/views/mixin.py @@ -179,27 +179,29 @@ class OrganizationCountsMixin(object): db_results['projects'] = project_qs.values('organization').annotate(Count('organization')).order_by('organization') - member_rd = RoleDefinition.objects.get(name='Organization Member') - admin_rd = RoleDefinition.objects.get(name='Organization Admin') + member_rd = RoleDefinition.objects.filter(name='Organization Member').first() + admin_rd = RoleDefinition.objects.filter(name='Organization Admin').first() - def assignment_count(rd): - return Coalesce( - Subquery( - RoleUserAssignment.objects.filter( - object_id=OuterRef('pk'), - role_definition=rd, - ) - .values('role_definition') - .annotate(c=Count('pk')) - .values('c') - ), - 0, - ) + if member_rd and admin_rd: - db_results['users'] = org_qs.annotate( - users=assignment_count(member_rd), - admins=assignment_count(admin_rd), - ).values('id', 'users', 'admins') + def assignment_count(rd): + return Coalesce( + Subquery( + RoleUserAssignment.objects.filter( + object_id=OuterRef('pk'), + role_definition=rd, + ) + .values('role_definition') + .annotate(c=Count('pk')) + .values('c') + ), + 0, + ) + + db_results['users'] = org_qs.annotate( + users=assignment_count(member_rd), + admins=assignment_count(admin_rd), + ).values('id', 'users', 'admins') count_context = {} for org in org_id_list: diff --git a/awx/api/views/organization.py b/awx/api/views/organization.py index 952ad8b286..ac2c871a96 100644 --- a/awx/api/views/organization.py +++ b/awx/api/views/organization.py @@ -79,36 +79,41 @@ class OrganizationDetail(RelatedJobsPreventDeleteMixin, RetrieveUpdateDestroyAPI org_counts = {} access_kwargs = {'accessor': self.request.user, 'role_field': 'read_role'} - member_rd = RoleDefinition.objects.get(name='Organization Member') - admin_rd = RoleDefinition.objects.get(name='Organization Admin') + member_rd = RoleDefinition.objects.filter(name='Organization Member').first() + admin_rd = RoleDefinition.objects.filter(name='Organization Admin').first() - def assignment_count(rd): - return Coalesce( - Subquery( - RoleUserAssignment.objects.filter( - object_id=OuterRef('pk'), - role_definition=rd, - ) - .values('role_definition') - .annotate(c=Count('pk')) - .values('c') - ), - 0, + if member_rd and admin_rd: + + def assignment_count(rd): + return Coalesce( + Subquery( + RoleUserAssignment.objects.filter( + object_id=OuterRef('pk'), + role_definition=rd, + ) + .values('role_definition') + .annotate(c=Count('pk')) + .values('c') + ), + 0, + ) + + direct_counts = ( + Organization.objects.filter(id=org_id) + .annotate( + users=assignment_count(member_rd), + admins=assignment_count(admin_rd), + ) + .values('users', 'admins') ) - direct_counts = ( - Organization.objects.filter(id=org_id) - .annotate( - users=assignment_count(member_rd), - admins=assignment_count(admin_rd), - ) - .values('users', 'admins') - ) + if direct_counts: + org_counts = direct_counts[0] + else: + org_counts = {'users': 0, 'admins': 0} - if not direct_counts: + if not org_counts: return full_context - - org_counts = direct_counts[0] org_counts['inventories'] = Inventory.accessible_objects(**access_kwargs).filter(organization__id=org_id).count() org_counts['teams'] = Team.accessible_objects(**access_kwargs).filter(organization__id=org_id).count() org_counts['projects'] = Project.accessible_objects(**access_kwargs).filter(organization__id=org_id).count()