diff --git a/src/documents/permissions.py b/src/documents/permissions.py index ea6b1bc672..08eda1f775 100644 --- a/src/documents/permissions.py +++ b/src/documents/permissions.py @@ -291,12 +291,19 @@ def get_permission_grantees( "permission__codename__in": list(action_by_codename), "object_pk__in": [str(pk) for pk in pks], } - for perm_model, identity_field, key in ( - (UserObjectPermission, "user_id", "users"), - (GroupObjectPermission, "group_id", "groups"), + for perm_model, identity_model, identity_field, key in ( + (UserObjectPermission, User, "user_id", "users"), + (GroupObjectPermission, Group, "group_id", "groups"), ): + # Every grant belongs to an existing user or group, so restricting to + # them changes no result. It lets MariaDB use guardian's + # (identity, content_type, object_pk) index; the content type alone + # matches every grant of the model and is scanned in full. rows = ( - perm_model.objects.filter(**grant_filter) + perm_model.objects.filter( + **{f"{identity_field}__in": identity_model.objects.values("pk")}, + **grant_filter, + ) .values_list("object_pk", "permission__codename", identity_field) .order_by(identity_field) ) diff --git a/src/documents/serialisers.py b/src/documents/serialisers.py index daef5b251a..c476a33d6a 100644 --- a/src/documents/serialisers.py +++ b/src/documents/serialisers.py @@ -397,10 +397,14 @@ class OwnedObjectSerializer( object_pks = list(obj.pk for obj in objects) pk_type = type(first_obj.pk) - def get_pks_for_permission_type(model): + def get_pks_for_permission_type(model, identity_field, identity_model): + # Restricting to existing users/groups changes no result but lets + # MariaDB use guardian's (identity, content_type, object_pk) index + # instead of scanning every grant of the model. return map( pk_type, # coerce the pk to be the same type of the provided objects model.objects.filter( + **{f"{identity_field}__in": identity_model.objects.values("pk")}, content_type=ctype, object_pk__in=object_pks, ) @@ -410,8 +414,16 @@ class OwnedObjectSerializer( UserObjectPermission = get_user_obj_perms_model() GroupObjectPermission = get_group_obj_perms_model() - user_permission_pks = get_pks_for_permission_type(UserObjectPermission) - group_permission_pks = get_pks_for_permission_type(GroupObjectPermission) + user_permission_pks = get_pks_for_permission_type( + UserObjectPermission, + "user_id", + User, + ) + group_permission_pks = get_pks_for_permission_type( + GroupObjectPermission, + "group_id", + Group, + ) return set(user_permission_pks) | set(group_permission_pks)