Skip to content

Commit b4e0952

Browse files
committed
improved comments on GameContentSerializer
1 parent af1ac1d commit b4e0952

File tree

1 file changed

+46
-20
lines changed

1 file changed

+46
-20
lines changed

api_v2/serializers/abstracts.py

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
from api_v2 import models
55

66
class GameContentSerializer(serializers.HyperlinkedModelSerializer):
7-
7+
"""
8+
Much of the logic included in the GameContentSerializer is intended to
9+
support manipulating data returned by the serializer via query parameters.
10+
"""
11+
812
def remove_unwanted_fields(self, dynamic_params):
913
"""
1014
Takes the value of the 'fields', a string of comma-separated values,
11-
and removes all other fields from the serializer
15+
and removes all fields not in this list from the serializer
1216
"""
1317
if fields_to_keep := dynamic_params.pop("fields", None):
1418
fields_to_keep = set(fields_to_keep.split(","))
@@ -27,12 +31,20 @@ def get_or_create_dynamic_params(self, child):
2731

2832
@staticmethod
2933
def split_param(dynamic_param):
34+
"""
35+
Splits a dynamic parameter into its target child serializer and value.
36+
Returns the values as a tuple.
37+
eg.
38+
'document__fields=name' -> ('document', 'fields=name')
39+
'document__gamesystem__fields=name' -> ('document', 'gamesystem__fields=name')
40+
"""
3041
crumbs = dynamic_param.split("__")
3142
return crumbs[0], "__".join(crumbs[1:]) if len(crumbs) > 1 else None
3243

3344
def set_dynamic_params_for_children(self, dynamic_params):
3445
"""
3546
Passes nested dynamic params to child serializer.
47+
eg. the param 'document__fields=name'
3648
"""
3749
for param, fields in dynamic_params.items():
3850
child, child_dynamic_param = self.split_param(param)
@@ -48,13 +60,26 @@ def set_dynamic_params_for_children(self, dynamic_params):
4860

4961
@staticmethod
5062
def is_param_dynamic(p):
63+
"""
64+
Returns true if parameter 'p' is a dynamic parameter. Currently the
65+
only dynamic param supported is 'fields', so we check for that
66+
"""
5167
return p.endswith("fields")
5268

5369
def get_dynamic_params_for_root(self, request):
70+
"""
71+
Returns a dict of dynamic query parameters extracted from the 'request'
72+
object. Only works on the root serializer (child serializers do no
73+
include a 'request' field)
74+
"""
5475
query_params = request.query_params.items()
5576
return {k: v for k, v in query_params if self.is_param_dynamic(k)}
5677

5778
def get_dynamic_params(self):
79+
"""
80+
Returns dynamic parameters stored on the serializer context
81+
"""
82+
# The context for ListSerializers is stored on the parent
5883
if isinstance(self.parent, serializers.ListSerializer):
5984
return self.parent._context.get("dynamic_params", {})
6085
return self._context.get("dynamic_params", {})
@@ -69,30 +94,34 @@ def handle_depth_serialization(self, instance, representation):
6994
max_depth = self._context.get("max_depth", 0)
7095
current_depth = self._context.get("current_depth", 0)
7196

72-
# if we reach the maximum depth, nested serializers return their pk
97+
# if we reach the maximum depth, nested serializers return their pk (url)
7398
if current_depth >= max_depth:
7499
for field_name, field in self.fields.items():
75100
if isinstance(field, serializers.HyperlinkedModelSerializer):
76101
nested_representation = representation.get(field_name)
77102
if nested_representation and "url" in nested_representation:
78103
representation[field_name] = nested_representation["url"]
104+
return representation
79105

80106
# otherwise, pass depth to children serializers
81-
else:
82-
for field_name, field in self.fields.items():
83-
if isinstance(field, GameContentSerializer):
84-
nested_instance = getattr(instance, field_name)
85-
nested_serializer = field.__class__(nested_instance, context={
86-
**self._context,
87-
"current_depth": current_depth + 1,
88-
"max_depth": max_depth,
89-
})
90-
# Ensure dynamic params are specific to the child serializer
91-
child_dynamic_params = self.get_or_create_dynamic_params(field_name)
92-
nested_serializer._context['dynamic_params'] = child_dynamic_params
93-
representation[field_name] = nested_serializer.data
94-
107+
for field_name, field in self.fields.items():
108+
# Guard clause: make sure the child is a GameContentSerializer
109+
if not isinstance(field, GameContentSerializer):
110+
continue
111+
112+
nested_instance = getattr(instance, field_name)
113+
nested_serializer = field.__class__(nested_instance, context={
114+
**self._context,
115+
"current_depth": current_depth + 1,
116+
"max_depth": max_depth,
117+
})
118+
119+
# Ensure dynamic params are specific to the child serializer
120+
child_dynamic_params = self.get_or_create_dynamic_params(field_name)
121+
nested_serializer._context['dynamic_params'] = child_dynamic_params
122+
representation[field_name] = nested_serializer.data
95123
return representation
124+
96125

97126
def __init__(self, *args, **kwargs):
98127
request = kwargs.get("context", {}).get("request")
@@ -104,9 +133,6 @@ def __init__(self, *args, **kwargs):
104133
self._context.update({"dynamic_params": dynamic_params})
105134

106135
def to_representation(self, instance):
107-
max_depth = self._context.get("max_depth", 0)
108-
current_depth = self._context.get("current_depth", 0)
109-
110136
if dynamic_params := self.get_dynamic_params().copy():
111137
self.remove_unwanted_fields(dynamic_params)
112138
self.set_dynamic_params_for_children(dynamic_params)

0 commit comments

Comments
 (0)