Skip to content

Allow specifying omit/fields params via the Serializer context #17

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
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
9 changes: 9 additions & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,15 @@ pass in the request through the context:
serializer = EventSerializer(events, many=True, context={'request': request})


In addition to using query parameters to pass ``omit`` and ``fields``, the
serializer context can be used as well (also taking precedence over the query):

.. sourcecode:: python

events = Event.objects.all()
context = {'request': request, 'omit': 'id,name'}
serializer = EventSerializer(events, many=True, context=context)

Testing
-------

Expand Down
33 changes: 26 additions & 7 deletions drf_dynamic_fields/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ class DynamicFieldsMixin(object):
which fields should be displayed.
"""

def _collect_params(self, request):
"""Params can be passed via the GET query or the serializer context.

Both sources are merged into a unique set, with the context
taking predecence over query parameters.

"""
params = getattr(
request, 'query_params', getattr(request, 'GET', None)
)

if params is not None:
params = params.copy()

for param_name in ('omit', 'fields'):
param_value = self.context.get(param_name, None)
if param_value is not None:
params[param_name] = param_value

return params

@property
def fields(self):
"""
Expand All @@ -29,7 +50,8 @@ def fields(self):
# Only filter if this is the root serializer, or if the parent is the
# root serializer with many=True
is_root = self.root == self
parent_is_list_root = self.parent == self.root and getattr(self.parent, 'many', False)
parent_is_list_root = (self.parent == self.root and
getattr(self.parent, 'many', False))
if not (is_root or parent_is_list_root):
return fields

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

# NOTE: drf test framework builds a request object where the query
# parameters are found under the GET attribute.
params = getattr(
request, 'query_params', getattr(request, 'GET', None)
)
params = self._collect_params(request)

if params is None:
warnings.warn('Request object does not contain query paramters')
warnings.warn('Request object does not contain query parameters')

try:
filter_fields = params.get('fields', None).split(',')
Expand Down
48 changes: 48 additions & 0 deletions tests/test_mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,51 @@ def test_as_nested_serializer(self):
],
}
)

def test_pass_params_via_serializer_context(self):
"""
Params can solely (or additionally) be passed via serializer context.
"""
rf = RequestFactory()
request = rf.get('/api/v1/schools/1/')
context = {
'request': request,
'omit': 'request_info',
}
serializer = TeacherSerializer(context=context)

self.assertEqual(
set(serializer.fields.keys()),
set(('id',))
)

def test_serializer_context_overwrites_query_params(self):
"""
Params passed via context take precedence over query_params.
"""
rf = RequestFactory()
request = rf.get('/api/v1/schools/1/?fields=request_info')
context = {
'request': request,
'fields': 'id',
}
serializer = TeacherSerializer(context=context)

self.assertEqual(
set(serializer.fields.keys()),
set(('id',))
)

def test_no_params_passed_at_all(self):
"""
Specifying neither query_params nor context params should not fail.
"""
rf = RequestFactory()
request = rf.get('/api/v1/schools/1/')
context = {'request': request}
serializer = TeacherSerializer(context=context)

self.assertEqual(
set(serializer.fields.keys()),
set(('id', 'request_info'))
)