Skip to content

Commit

Permalink
fixed bug with 'field' filters propagating to child serializers
Browse files Browse the repository at this point in the history
  • Loading branch information
calumbell committed Nov 4, 2024
1 parent 00675cd commit af1ac1d
Showing 1 changed file with 46 additions and 19 deletions.
65 changes: 46 additions & 19 deletions api_v2/serializers/abstracts.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,15 @@ def set_dynamic_params_for_children(self, dynamic_params):
"""
for param, fields in dynamic_params.items():
child, child_dynamic_param = self.split_param(param)
if child in set(self.fields.keys()):
dynamic_params = self.get_or_create_dynamic_params(child)
dynamic_params.update({child_dynamic_param: fields})
if child in self.fields.keys():
# Get dynamic parameters for child serializer and update
child_dynamic_params = self.get_or_create_dynamic_params(child)
child_dynamic_params.update({child_dynamic_param: fields})

# Overwrite existing params to remove 'fields' inherited from parent serializer
self.fields[child]._context['dynamic_params'] = {
**child_dynamic_params,
}

@staticmethod
def is_param_dynamic(p):
Expand All @@ -53,6 +59,41 @@ def get_dynamic_params(self):
return self.parent._context.get("dynamic_params", {})
return self._context.get("dynamic_params", {})

def handle_depth_serialization(self, instance, representation):
"""
Handles the serialization of fields based on the current depth
compared to the maximum allowed depth. This function modifies
the representation to include only URLs for nested serializers
when the maximum depth is reached.
"""
max_depth = self._context.get("max_depth", 0)
current_depth = self._context.get("current_depth", 0)

# if we reach the maximum depth, nested serializers return their pk
if current_depth >= max_depth:
for field_name, field in self.fields.items():
if isinstance(field, serializers.HyperlinkedModelSerializer):
nested_representation = representation.get(field_name)
if nested_representation and "url" in nested_representation:
representation[field_name] = nested_representation["url"]

# otherwise, pass depth to children serializers
else:
for field_name, field in self.fields.items():
if isinstance(field, GameContentSerializer):
nested_instance = getattr(instance, field_name)
nested_serializer = field.__class__(nested_instance, context={
**self._context,
"current_depth": current_depth + 1,
"max_depth": max_depth,
})
# Ensure dynamic params are specific to the child serializer
child_dynamic_params = self.get_or_create_dynamic_params(field_name)
nested_serializer._context['dynamic_params'] = child_dynamic_params
representation[field_name] = nested_serializer.data

return representation

def __init__(self, *args, **kwargs):
request = kwargs.get("context", {}).get("request")
super().__init__(*args, **kwargs)
Expand All @@ -66,30 +107,16 @@ def to_representation(self, instance):
max_depth = self._context.get("max_depth", 0)
current_depth = self._context.get("current_depth", 0)

# Process dynamic parameters for filtering fields
if dynamic_params := self.get_dynamic_params().copy():
self.remove_unwanted_fields(dynamic_params)
self.set_dynamic_params_for_children(dynamic_params)

# Collect only the fields that need to be included in the representation
representation = super().to_representation(instance)

if current_depth >= max_depth:
# Remove fields that are HyperlinkedModelSerializers (nested fields)
for field_name, field in self.fields.items():
if isinstance(field, serializers.HyperlinkedModelSerializer):
# Check if the nested field has a 'url' attribute in the representation
nested_representation = representation.get(field_name)
if nested_representation and "url" in nested_representation:
# Replace the entire nested structure with the URL field
representation[field_name] = nested_representation["url"]
else:
# Update depth level in children
for field_name, field in self.fields.items():
if isinstance(field, GameContentSerializer):
field._context["current_depth"] = current_depth + 1
representation = self.handle_depth_serialization(instance, representation)

return representation


class Meta:
abstract = True

0 comments on commit af1ac1d

Please sign in to comment.