From 1f924ac0d097a9ed28872ece6a33eb0f6db9aa19 Mon Sep 17 00:00:00 2001 From: Jozef Knaperek Date: Fri, 3 Jun 2016 11:04:00 +0200 Subject: [PATCH 1/4] Add option to specify default included resources Let's provide an extra JSONAPIMeta configuration option that specifies resources to be listed in the 'included' section of the response. These resources shall be included even if they're not explicitly mentioned in the 'include' request parameter. --- rest_framework_json_api/renderers.py | 13 +++++++------ rest_framework_json_api/utils.py | 7 +++++++ 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/rest_framework_json_api/renderers.py b/rest_framework_json_api/renderers.py index 1c66c927..f0824d50 100644 --- a/rest_framework_json_api/renderers.py +++ b/rest_framework_json_api/renderers.py @@ -415,12 +415,6 @@ def render(self, data, accepted_media_type=None, renderer_context=None): if resource_name == 'errors': return self.render_errors(data, accepted_media_type, renderer_context) - include_resources_param = request.query_params.get('include') if request else None - if include_resources_param: - included_resources = include_resources_param.split(',') - else: - included_resources = list() - json_api_data = data json_api_included = list() # initialize json_api_meta with pagination meta or an empty dict @@ -433,6 +427,13 @@ def render(self, data, accepted_media_type=None, renderer_context=None): serializer = getattr(serializer_data, 'serializer', None) + # Build a list of included resources + included_resources = utils.get_default_included_resources_from_serializer(serializer) + include_resources_param = request.query_params.get('include') if request else None + if include_resources_param: + extra = filter(lambda r: r not in included_resources, include_resources_param.split(',')) + included_resources.extend(extra) + if serializer is not None: # Get the serializer fields diff --git a/rest_framework_json_api/utils.py b/rest_framework_json_api/utils.py index 261640c6..bd7d013d 100644 --- a/rest_framework_json_api/utils.py +++ b/rest_framework_json_api/utils.py @@ -232,6 +232,13 @@ def get_resource_type_from_serializer(serializer): return get_resource_type_from_model(serializer.Meta.model) +def get_default_included_resources_from_serializer(serializer): + try: + return list(serializer.JSONAPIMeta.included_resources) + except AttributeError: + return [] + + def get_included_serializers(serializer): included_serializers = copy.copy(getattr(serializer, 'included_serializers', dict())) From f915756c1431f287a330ceb3eb40c982424052ae Mon Sep 17 00:00:00 2001 From: Jozef Knaperek Date: Fri, 3 Jun 2016 14:31:42 +0200 Subject: [PATCH 2/4] Re-trigger Travis Build script The previous build failure was caused by some random environment issue. From 98a48151fcfdeed8c55abc46ccafd42055a486c6 Mon Sep 17 00:00:00 2001 From: Jozef Knaperek Date: Fri, 3 Jun 2016 15:54:57 +0200 Subject: [PATCH 3/4] Ignore default 'included' resources if specified in request Conform to the specs and ensure that no other resources are included in the response other than those explicitely requested inside the 'include' parameter in request. --- rest_framework_json_api/renderers.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rest_framework_json_api/renderers.py b/rest_framework_json_api/renderers.py index f0824d50..0a11063e 100644 --- a/rest_framework_json_api/renderers.py +++ b/rest_framework_json_api/renderers.py @@ -428,11 +428,11 @@ def render(self, data, accepted_media_type=None, renderer_context=None): serializer = getattr(serializer_data, 'serializer', None) # Build a list of included resources - included_resources = utils.get_default_included_resources_from_serializer(serializer) include_resources_param = request.query_params.get('include') if request else None if include_resources_param: - extra = filter(lambda r: r not in included_resources, include_resources_param.split(',')) - included_resources.extend(extra) + included_resources = include_resources_param.split(',') + else: + included_resources = utils.get_default_included_resources_from_serializer(serializer) if serializer is not None: From ef72e1a6cfad1b6d51818b0045564225610befa7 Mon Sep 17 00:00:00 2001 From: Jozef Knaperek Date: 2016年6月21日 10:40:58 +0200 Subject: [PATCH 4/4] Add tests for default included_resources feature --- example/tests/integration/test_includes.py | 20 ++++++++++++++++---- requirements-development.txt | 1 + 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/example/tests/integration/test_includes.py b/example/tests/integration/test_includes.py index 05c59131..8e2a7a2a 100644 --- a/example/tests/integration/test_includes.py +++ b/example/tests/integration/test_includes.py @@ -2,12 +2,19 @@ from django.core.urlresolvers import reverse from example.tests.utils import load_json +import mock pytestmark = pytest.mark.django_db -def test_included_data_on_list(multiple_entries, client): - response = client.get(reverse("entry-list") + '?include=comments&page_size=5') + +@mock.patch('rest_framework_json_api.utils.get_default_included_resources_from_serializer', new=lambda s: ['comments']) +def test_default_included_data_on_list(multiple_entries, client): + return test_included_data_on_list(multiple_entries=multiple_entries, client=client, query='?page_size=5') + + +def test_included_data_on_list(multiple_entries, client, query='?include=comments&page_size=5'): + response = client.get(reverse("entry-list") + query) included = load_json(response.content).get('included') assert len(load_json(response.content)['data']) == len(multiple_entries), 'Incorrect entry count' @@ -18,8 +25,13 @@ def test_included_data_on_list(multiple_entries, client): assert comment_count == expected_comment_count, 'List comment count is incorrect' -def test_included_data_on_detail(single_entry, client): - response = client.get(reverse("entry-detail", kwargs={'pk': single_entry.pk}) + '?include=comments') +@mock.patch('rest_framework_json_api.utils.get_default_included_resources_from_serializer', new=lambda s: ['comments']) +def test_default_included_data_on_detail(single_entry, client): + return test_included_data_on_detail(single_entry=single_entry, client=client, query='') + + +def test_included_data_on_detail(single_entry, client, query='?include=comments'): + response = client.get(reverse("entry-detail", kwargs={'pk': single_entry.pk}) + query) included = load_json(response.content).get('included') assert [x.get('type') for x in included] == ['comments'], 'Detail included types are incorrect' diff --git a/requirements-development.txt b/requirements-development.txt index 6aa243bd..78ccdc91 100644 --- a/requirements-development.txt +++ b/requirements-development.txt @@ -4,3 +4,4 @@ pytest-django pytest-factoryboy fake-factory tox +mock

AltStyle によって変換されたページ (->オリジナル) /