diff --git a/example/tests/test_relations.py b/example/tests/test_relations.py index bf2bfed7..1fe5b537 100644 --- a/example/tests/test_relations.py +++ b/example/tests/test_relations.py @@ -7,6 +7,7 @@ from rest_framework_json_api.exceptions import Conflict from rest_framework_json_api.utils import format_relation_name from example.models import Blog, Entry, Comment, Author +from example.serializers import CommentSerializer from rest_framework_json_api.relations import ResourceRelatedField @@ -115,6 +116,15 @@ def test_read_only(self): serializer.is_valid(raise_exception=True) self.assertNotIn('comment_set', serializer.validated_data) + def test_invalid_resource_id_object(self): + comment = {'body': 'testing 123', 'entry': {'type': 'entry'}, 'author': {'id': '5'}} + serializer = CommentSerializer(data=comment) + assert not serializer.is_valid() + assert serializer.errors == { + 'author': ["Invalid resource identifier object: missing 'type' attribute"], + 'entry': ["Invalid resource identifier object: missing 'id' attribute"] + } + class BlogFKSerializer(serializers.Serializer): blog = ResourceRelatedField(queryset=Blog.objects) diff --git a/rest_framework_json_api/relations.py b/rest_framework_json_api/relations.py index 61b9ecd7..bd53b205 100644 --- a/rest_framework_json_api/relations.py +++ b/rest_framework_json_api/relations.py @@ -19,6 +19,8 @@ class ResourceRelatedField(PrimaryKeyRelatedField): 'does_not_exist': _('Invalid pk "{pk_value}" - object does not exist.'), 'incorrect_type': _('Incorrect type. Expected resource identifier object, received {data_type}.'), 'incorrect_relation_type': _('Incorrect relation type. Expected {relation_type}, received {received_type}.'), + 'missing_type': _('Invalid resource identifier object: missing \'type\' attribute'), + 'missing_id': _('Invalid resource identifier object: missing \'id\' attribute'), 'no_match': _('Invalid hyperlink - No URL match.'), } @@ -117,8 +119,16 @@ def to_internal_value(self, data): if not isinstance(data, dict): self.fail('incorrect_type', data_type=type(data).__name__) expected_relation_type = get_resource_type_from_queryset(self.queryset) + + if 'type' not in data: + self.fail('missing_type') + + if 'id' not in data: + self.fail('missing_id') + if data['type'] != expected_relation_type: self.conflict('incorrect_relation_type', relation_type=expected_relation_type, received_type=data['type']) + return super(ResourceRelatedField, self).to_internal_value(data['id']) def to_representation(self, value):