Skip to content

Commit 817e49c

Browse files
committed
Use the serializer context as optional params source.
This allows passing omit/fields values to drf-dynamic-fields from a lower level API, useful when creating serializers manually, e.g. inside other serializers.
1 parent c101277 commit 817e49c

File tree

2 files changed

+74
-7
lines changed

2 files changed

+74
-7
lines changed

drf_dynamic_fields/__init__.py

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,27 @@ class DynamicFieldsMixin(object):
1010
which fields should be displayed.
1111
"""
1212

13+
def _collect_params(self, request):
14+
"""Params can be passed via the GET query or the serializer context.
15+
16+
Both sources are merged into a unique set, with the context
17+
taking predecence over query parameters.
18+
19+
"""
20+
params = getattr(
21+
request, 'query_params', getattr(request, 'GET', None)
22+
)
23+
24+
if params is not None:
25+
params = params.copy()
26+
27+
for param_name in ('omit', 'fields'):
28+
param_value = self.context.get(param_name, None)
29+
if param_value is not None:
30+
params[param_name] = param_value
31+
32+
return params
33+
1334
@property
1435
def fields(self):
1536
"""
@@ -29,7 +50,8 @@ def fields(self):
2950
# Only filter if this is the root serializer, or if the parent is the
3051
# root serializer with many=True
3152
is_root = self.root == self
32-
parent_is_list_root = self.parent == self.root and getattr(self.parent, 'many', False)
53+
parent_is_list_root = (self.parent == self.root and
54+
getattr(self.parent, 'many', False))
3355
if not (is_root or parent_is_list_root):
3456
return fields
3557

@@ -39,13 +61,10 @@ def fields(self):
3961
warnings.warn('Context does not have access to request')
4062
return fields
4163

42-
# NOTE: drf test framework builds a request object where the query
43-
# parameters are found under the GET attribute.
44-
params = getattr(
45-
request, 'query_params', getattr(request, 'GET', None)
46-
)
64+
params = self._collect_params(request)
65+
4766
if params is None:
48-
warnings.warn('Request object does not contain query paramters')
67+
warnings.warn('Request object does not contain query parameters')
4968

5069
try:
5170
filter_fields = params.get('fields', None).split(',')

tests/test_mixins.py

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -169,3 +169,51 @@ def test_as_nested_serializer(self):
169169
],
170170
}
171171
)
172+
173+
def test_pass_params_via_serializer_context(self):
174+
"""
175+
Params can solely (or additionally) be passed via serializer context.
176+
"""
177+
rf = RequestFactory()
178+
request = rf.get('/api/v1/schools/1/')
179+
context = {
180+
'request': request,
181+
'omit': 'request_info',
182+
}
183+
serializer = TeacherSerializer(context=context)
184+
185+
self.assertEqual(
186+
set(serializer.fields.keys()),
187+
set(('id',))
188+
)
189+
190+
def test_serializer_context_overwrites_query_params(self):
191+
"""
192+
Params passed via context take precedence over query_params.
193+
"""
194+
rf = RequestFactory()
195+
request = rf.get('/api/v1/schools/1/?fields=request_info')
196+
context = {
197+
'request': request,
198+
'fields': 'id',
199+
}
200+
serializer = TeacherSerializer(context=context)
201+
202+
self.assertEqual(
203+
set(serializer.fields.keys()),
204+
set(('id',))
205+
)
206+
207+
def test_no_params_passed_at_all(self):
208+
"""
209+
Specifying neither query_params nor context params should not fail.
210+
"""
211+
rf = RequestFactory()
212+
request = rf.get('/api/v1/schools/1/')
213+
context = {'request': request}
214+
serializer = TeacherSerializer(context=context)
215+
216+
self.assertEqual(
217+
set(serializer.fields.keys()),
218+
set(('id', 'request_info'))
219+
)

0 commit comments

Comments
 (0)