Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 33 additions & 1 deletion authentik/core/api/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,28 @@ class PartialUserSerializer(ModelSerializer):
attributes = JSONDictField(required=False)
uid = CharField(read_only=True)

def to_representation(self, instance):
"""Override to use request-level cache for serialized users.

When the same user appears in multiple groups, we cache their serialized
representation to avoid redundant serialization work.
"""
request = self.context.get('request')
cache = getattr(request, '_user_serialization_cache', None) if request else None

if cache is not None:
# Check if already serialized
if instance.pk in cache:
return cache[instance.pk]

# Serialize and cache
result = super().to_representation(instance)
cache[instance.pk] = result
return result

# No cache available, serialize normally
return super().to_representation(instance)

class Meta:
model = User
fields = [
Expand Down Expand Up @@ -98,7 +120,8 @@ def _should_include_children(self) -> bool:
def get_users_obj(self, instance: Group) -> list[PartialUserSerializer] | None:
if not self._should_include_users:
return None
return PartialUserSerializer(instance.users, many=True).data
# Use .all() to access prefetched data and pass context for cache
return PartialUserSerializer(instance.users.all(), many=True, context=self.context).data

@extend_schema_field(GroupChildSerializer(many=True))
def get_children_obj(self, instance: Group) -> list[GroupChildSerializer] | None:
Expand Down Expand Up @@ -228,6 +251,15 @@ class UserAccountSerializer(PassiveSerializer):
filterset_class = GroupFilter
ordering = ["name"]

def initialize_request(self, request, *args, **kwargs):
"""Initialize request with a cache for serialized users.
This cache prevents re-serializing the same user when they appear in
multiple groups within the same request."""

request = super().initialize_request(request, *args, **kwargs)
request._user_serialization_cache = {}
return request

def get_ql_fields(self):
from djangoql.schema import BoolField, StrField

Expand Down