diff --git a/AUTHORS b/AUTHORS index f3e3d2b2..0f4c5167 100644 --- a/AUTHORS +++ b/AUTHORS @@ -22,3 +22,4 @@ Yaniv Peer Mohammed Ali Zubair Jason Housley Beni Keller +Stas S. diff --git a/CHANGELOG.md b/CHANGELOG.md index d193884b..19ce7f65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Note that in line with [Django REST Framework policy](http://www.django-rest-framework.org/topics/release-notes/), any parts of the framework not mentioned in the documentation should generally be considered private API, and may be subject to change. +## [Unreleased] + +### Fixed + +* Avoid exception when trying to include skipped relationship ## [2.7.0] - 2019-01-14 diff --git a/example/serializers.py b/example/serializers.py index 7917062e..9be6d4d7 100644 --- a/example/serializers.py +++ b/example/serializers.py @@ -1,6 +1,6 @@ from datetime import datetime -from rest_framework import serializers as drf_serilazers +from rest_framework import serializers as drf_serilazers, fields as drf_fields from rest_framework_json_api import relations, serializers @@ -318,15 +318,40 @@ class Meta: exclude = ('polymorphic_ctype',) +class CurrentProjectRelatedField(relations.PolymorphicResourceRelatedField): + def get_attribute(self, instance): + obj = super(CurrentProjectRelatedField, self).get_attribute(instance) + + is_art = ( + self.field_name == 'current_art_project' and + isinstance(obj, ArtProject) + ) + is_res = ( + self.field_name == 'current_research_project' and + isinstance(obj, ResearchProject) + ) + + if is_art or is_res: + return obj + + raise drf_fields.SkipField() + + class CompanySerializer(serializers.ModelSerializer): current_project = relations.PolymorphicResourceRelatedField( ProjectSerializer, queryset=Project.objects.all()) + current_art_project = CurrentProjectRelatedField( + ProjectSerializer, source='current_project', read_only=True) + current_research_project = CurrentProjectRelatedField( + ProjectSerializer, source='current_project', read_only=True) future_projects = relations.PolymorphicResourceRelatedField( ProjectSerializer, queryset=Project.objects.all(), many=True) included_serializers = { 'current_project': ProjectSerializer, 'future_projects': ProjectSerializer, + 'current_art_project': ProjectSerializer, + 'current_research_project': ProjectSerializer } class Meta: diff --git a/example/tests/integration/test_polymorphism.py b/example/tests/integration/test_polymorphism.py index bc80599a..48ee80f3 100644 --- a/example/tests/integration/test_polymorphism.py +++ b/example/tests/integration/test_polymorphism.py @@ -25,10 +25,13 @@ def test_polymorphism_on_detail_relations(single_company, client): def test_polymorphism_on_included_relations(single_company, client): - response = client.get(reverse("company-detail", kwargs={'pk': single_company.pk}) + - '?include=current_project,future_projects') + response = client.get( + reverse("company-detail", kwargs={'pk': single_company.pk}) + + '?include=current_project,future_projects,current_art_project,current_research_project') content = response.json() assert content["data"]["relationships"]["currentProject"]["data"]["type"] == "artProjects" + assert content["data"]["relationships"]["currentArtProject"]["data"]["type"] == "artProjects" + assert content["data"]["relationships"]["currentResearchProject"]["data"] is None assert ( set([rel["type"] for rel in content["data"]["relationships"]["futureProjects"]["data"]]) == set(["researchProjects", "artProjects"]) diff --git a/rest_framework_json_api/renderers.py b/rest_framework_json_api/renderers.py index 9aa16212..d83fcdf0 100644 --- a/rest_framework_json_api/renderers.py +++ b/rest_framework_json_api/renderers.py @@ -375,7 +375,7 @@ def extract_included(cls, fields, resource, resource_instance, included_resource serializer_data = field.data if isinstance(field, relations.RelatedField): - if relation_instance is None: + if relation_instance is None or not serializer_data: continue many = field._kwargs.get('child_relation', None) is not None