def test_get_resource_name():
    view = APIView()
    context = {'view': view}
    setattr(settings, 'JSON_API_FORMAT_TYPES', None)
    assert 'APIViews' == utils.get_resource_name(context), 'not formatted'

    context = {'view': view}
    setattr(settings, 'JSON_API_FORMAT_TYPES', 'dasherize')
    assert 'api-views' == utils.get_resource_name(context), 'derived from view'

    view.model = get_user_model()
    assert 'users' == utils.get_resource_name(context), 'derived from view model'

    view.resource_name = 'custom'
    assert 'custom' == utils.get_resource_name(context), 'manually set on view'

    view.response = Response(status=403)
    assert 'errors' == utils.get_resource_name(context), 'handles 4xx error'

    view.response = Response(status=500)
    assert 'errors' == utils.get_resource_name(context), 'handles 500 error'

    view = GenericAPIView()
    view.serializer_class = ResourceSerializer
    context = {'view': view}
    assert 'users' == utils.get_resource_name(context), 'derived from serializer'

    view.serializer_class.Meta.resource_name = 'rcustom'
    assert 'rcustom' == utils.get_resource_name(context), 'set on serializer'

    view = GenericAPIView()
    view.serializer_class = NonModelResourceSerializer
    context = {'view': view}
    assert 'users' == utils.get_resource_name(context), 'derived from non-model serializer'
def test_get_resource_name():
    view = APIView()
    context = {'view': view}
    with override_settings(JSON_API_FORMAT_TYPES=None):
        assert 'APIViews' == utils.get_resource_name(context), 'not formatted'

    context = {'view': view}
    with override_settings(JSON_API_FORMAT_TYPES='dasherize'):
        assert 'api-views' == utils.get_resource_name(context), 'derived from view'

    view.model = get_user_model()
    assert 'users' == utils.get_resource_name(context), 'derived from view model'

    view.resource_name = 'custom'
    assert 'custom' == utils.get_resource_name(context), 'manually set on view'

    view.response = Response(status=403)
    assert 'errors' == utils.get_resource_name(context), 'handles 4xx error'

    view.response = Response(status=500)
    assert 'errors' == utils.get_resource_name(context), 'handles 500 error'

    view = GenericAPIView()
    view.serializer_class = ResourceSerializer
    context = {'view': view}
    assert 'users' == utils.get_resource_name(context), 'derived from serializer'

    view.serializer_class.Meta.resource_name = 'rcustom'
    assert 'rcustom' == utils.get_resource_name(context), 'set on serializer'

    view = GenericAPIView()
    view.serializer_class = NonModelResourceSerializer
    context = {'view': view}
    assert 'users' == utils.get_resource_name(context), 'derived from non-model serializer'
Exemple #3
0
def test_get_resource_name_from_view(settings, format_type, pluralize_type, output):
    settings.JSON_API_FORMAT_TYPES = format_type
    settings.JSON_API_PLURALIZE_TYPES = pluralize_type

    view = APIView()
    context = {"view": view}
    assert output == get_resource_name(context)
Exemple #4
0
    def field_to_swagger_object(self,
                                field,
                                swagger_object_type,
                                use_references,
                                included=False,
                                is_request=None,
                                **kwargs):
        if not self.is_json_api_root_serializer(field, is_request):
            if self.handle_json_api_only:
                return inspectors.NotHandled
            else:
                return super().field_to_swagger_object(field,
                                                       swagger_object_type,
                                                       use_references,
                                                       **kwargs)

        if is_request is None and included:
            is_request = False

        if included:
            resource_name = get_resource_type_from_serializer(field)
        else:
            resource_name = get_resource_name(context={'view': self.view})

        SwaggerType, ChildSwaggerType = self._get_partial_types(
            field, swagger_object_type, use_references, **kwargs)
        return self.build_serializer_schema(field, resource_name, SwaggerType,
                                            ChildSwaggerType, use_references,
                                            is_request)
    def render(self, data, accepted_media_type=None, renderer_context=None):
        try:
            # Get the resource name.
            resource_name = utils.get_resource_name(renderer_context)

            # If this is an error response, skip the rest.
            if resource_name == 'errors':
                return self.render_errors(data, accepted_media_type,
                                          renderer_context)
        except:
            pass

        response = renderer_context['response']
        if response.status_code == HTTP_204_NO_CONTENT:
            return super(CustomJsonRender,
                         self).render(data=data,
                                      accepted_media_type=accepted_media_type,
                                      renderer_context=renderer_context)
        meta_data = {"include": [], "custom": []}

        if data and 'pagination' in data:
            meta_data["pagination"] = data.pop('pagination')
            data = data["data"]
        render_data = {"data": data, "meta": meta_data}
        return super(CustomJsonRender,
                     self).render(data=render_data,
                                  accepted_media_type=accepted_media_type,
                                  renderer_context=renderer_context)
def test_get_resource_name_from_view_custom_resource_name(
        settings, format_type, pluralize_type):
    settings.JSON_API_FORMAT_TYPES = format_type
    settings.JSON_API_PLURALIZE_TYPES = pluralize_type

    view = APIView()
    view.resource_name = "custom"
    context = {"view": view}
    assert "custom" == get_resource_name(context)
def test_get_resource_name_from_model_serializer_class(settings, format_type,
                                                       pluralize_type, output):
    settings.JSON_API_FORMAT_TYPES = format_type
    settings.JSON_API_PLURALIZE_TYPES = pluralize_type

    view = GenericAPIView()
    view.serializer_class = BasicModelSerializer
    context = {"view": view}
    assert output == get_resource_name(context)
Exemple #8
0
    def parse(self, stream, media_type=None, parser_context=None):
        """
        Parses the incoming bytestream as JSON and returns the resulting data
        """
        if hasattr(stream, 'raw_body'):
            result = stream.raw_body
        else:
            # Handles requests created by Django's test client, which is missing the raw_body attribute set in
            # the Django request-like object initialized by our zc_event event client
            try:
                result = ujson.loads(stream.body)
            except ValueError:
                result = {}

        data = result.get('data')

        if data:
            from rest_framework_json_api.views import RelationshipView
            if isinstance(parser_context['view'], RelationshipView):
                # We skip parsing the object as JSONAPI Resource Identifier Object and not a regular Resource Object
                if isinstance(data, list):
                    for resource_identifier_object in data:
                        if not (resource_identifier_object.get('id')
                                and resource_identifier_object.get('type')):
                            raise ParseError(
                                'Received data contains one or more malformed JSONAPI Resource Identifier Object(s)'
                            )
                elif not (data.get('id') and data.get('type')):
                    raise ParseError(
                        'Received data is not a valid JSONAPI Resource Identifier Object'
                    )

                return data

            request = parser_context.get('request')

            # Check for inconsistencies
            resource_name = utils.get_resource_name(parser_context)
            view = parser_context.get('view')
            if data.get('type') != resource_name and request.method in (
                    'PUT', 'POST', 'PATCH'):
                raise exceptions.Conflict(
                    "The resource object's type ({data_type}) is not the type "
                    "that constitute the collection represented by the endpoint ({resource_type})."
                    .format(data_type=data.get('type'),
                            resource_type=resource_name))

            # Construct the return data
            parsed_data = {'id': data.get('id')}
            parsed_data.update(self.parse_attributes(data))
            parsed_data.update(self.parse_relationships(data))
            parsed_data.update(self.parse_metadata(result))
            return parsed_data

        else:
            raise ParseError('Received document does not contain primary data')
def test_get_resource_name_from_model_serializer_class_custom_resource_name(
        settings, format_type, pluralize_type):
    settings.JSON_API_FORMAT_TYPES = format_type
    settings.JSON_API_PLURALIZE_TYPES = pluralize_type

    view = GenericAPIView()
    view.serializer_class = BasicModelSerializer
    view.serializer_class.Meta.resource_name = "custom"

    context = {"view": view}
    assert "custom" == get_resource_name(context)
def test_get_resource_name_from_plain_serializer_class(settings, format_type,
                                                       pluralize_type):
    class PlainSerializer(serializers.Serializer):
        class Meta:
            resource_name = "custom"

    settings.JSON_API_FORMAT_TYPES = format_type
    settings.JSON_API_PLURALIZE_TYPES = pluralize_type

    view = GenericAPIView()
    view.serializer_class = PlainSerializer

    context = {"view": view}
    assert "custom" == get_resource_name(context)
Exemple #11
0
    def parse(self, stream, media_type=None, parser_context=None):
        """
        Parses the incoming bytestream as JSON and returns the resulting data
        """
        result = super(JSONParser, self).parse(stream, media_type=media_type, parser_context=parser_context)

        data = result.get('data')

        if data:
            from rest_framework_json_api.views import RelationshipView
            if isinstance(parser_context['view'], RelationshipView):
                # We skip parsing the object as JSONAPI Resource Identifier Object and not a regular Resource Object
                if isinstance(data, list):
                    for resource_identifier_object in data:
                        if not (resource_identifier_object.get('id') and resource_identifier_object.get('type')):
                            raise ParseError(
                                'Received data contains one or more malformed JSONAPI Resource Identifier Object(s)'
                            )
                elif not (data.get('id') and data.get('type')):
                    raise ParseError('Received data is not a valid JSONAPI Resource Identifier Object')

                return data

            request = parser_context.get('request')

            # Check for inconsistencies
            resource_name = utils.get_resource_name(parser_context)
            view = parser_context.get('view')
            if data.get('type') != resource_name and request.method in ('PUT', 'POST', 'PATCH'):
                raise exceptions.Conflict(
                    "The resource object's type ({data_type}) is not the type "
                    "that constitute the collection represented by the endpoint ({resource_type}).".format(
                        data_type=data.get('type'),
                        resource_type=resource_name
                    )
                )

            # Construct the return data
            parsed_data = {'id': data.get('id')}
            parsed_data.update(self.parse_attributes(data))
            parsed_data.update(self.parse_relationships(data))
            parsed_data.update(self.parse_metadata(result))
            return parsed_data

        else:
            raise ParseError('Received document does not contain primary data')
    def field_to_swagger_object(self,
                                field,
                                swagger_object_type,
                                use_references,
                                included=False,
                                is_request=None,
                                **kwargs):
        if not self.is_json_api_root_serializer(field, is_request):
            return super().field_to_swagger_object(field, swagger_object_type,
                                                   use_references, **kwargs)

        SwaggerType, ChildSwaggerType = self._get_partial_types(
            field, swagger_object_type, use_references, **kwargs)

        resource_name = get_resource_type_from_serializer(field) if included \
            else get_resource_name(context={'view': self.view})

        return self.build_json_resource_schema(field, resource_name,
                                               SwaggerType, ChildSwaggerType,
                                               use_references, is_request)
    def render(self, data, accepted_media_type=None, renderer_context=None):

        renderer_context = renderer_context or {}

        view = renderer_context.get("view", None)
        request = renderer_context.get("request", None)

        # Get the resource name.
        resource_name = utils.get_resource_name(renderer_context)

        # If this is an error response, skip the rest.
        if resource_name == "errors":
            return self.render_errors(data, accepted_media_type,
                                      renderer_context)

        # if response.status_code is 204 then the data to be rendered must
        # be None
        response = renderer_context.get("response", None)
        if response is not None and response.status_code == 204:
            return super().render(None, accepted_media_type, renderer_context)

        from rest_framework_json_api.views import RelationshipView

        if isinstance(view, RelationshipView):
            return self.render_relationship_view(data, accepted_media_type,
                                                 renderer_context)

        # If `resource_name` is set to None then render default as the dev
        # wants to build the output format manually.
        if resource_name is None or resource_name is False:
            return super().render(data, accepted_media_type, renderer_context)

        json_api_data = data
        # initialize json_api_meta with pagination meta or an empty dict
        json_api_meta = data.get("meta", {}) if isinstance(data, dict) else {}
        included_cache = defaultdict(dict)

        if data and "results" in data:
            serializer_data = data["results"]
        else:
            serializer_data = data

        serializer = getattr(serializer_data, "serializer", None)

        included_resources = utils.get_included_resources(request, serializer)

        if serializer is not None:

            # Extract root meta for any type of serializer
            json_api_meta.update(
                self.extract_root_meta(serializer, serializer_data))

            if getattr(serializer, "many", False):
                json_api_data = list()

                for position in range(len(serializer_data)):
                    resource = serializer_data[
                        position]  # Get current resource
                    resource_instance = serializer.instance[
                        position]  # Get current instance

                    if isinstance(
                            serializer.child,
                            rest_framework_json_api.serializers.
                            PolymorphicModelSerializer,
                    ):
                        resource_serializer_class = (
                            serializer.child.
                            get_polymorphic_serializer_for_instance(
                                resource_instance)(
                                    context=serializer.child.context))
                    else:
                        resource_serializer_class = serializer.child

                    fields = utils.get_serializer_fields(
                        resource_serializer_class)
                    force_type_resolution = getattr(
                        resource_serializer_class,
                        "_poly_force_type_resolution", False)

                    json_resource_obj = self.build_json_resource_obj(
                        fields,
                        resource,
                        resource_instance,
                        resource_name,
                        serializer,
                        force_type_resolution,
                    )
                    json_api_data.append(json_resource_obj)

                    self.extract_included(
                        fields,
                        resource,
                        resource_instance,
                        included_resources,
                        included_cache,
                    )
            else:
                fields = utils.get_serializer_fields(serializer)
                force_type_resolution = getattr(serializer,
                                                "_poly_force_type_resolution",
                                                False)

                resource_instance = serializer.instance
                json_api_data = self.build_json_resource_obj(
                    fields,
                    serializer_data,
                    resource_instance,
                    resource_name,
                    serializer,
                    force_type_resolution,
                )

                self.extract_included(
                    fields,
                    serializer_data,
                    resource_instance,
                    included_resources,
                    included_cache,
                )

        # Make sure we render data in a specific order
        render_data = OrderedDict()

        if isinstance(data, dict) and data.get("links"):
            render_data["links"] = data.get("links")

        # format the api root link list
        if view.__class__ and view.__class__.__name__ == "APIRoot":
            render_data["data"] = None
            render_data["links"] = json_api_data
        else:
            render_data["data"] = json_api_data

        if included_cache:
            if isinstance(json_api_data, list):
                objects = json_api_data
            else:
                objects = [json_api_data]

            for object in objects:
                obj_type = object.get("type")
                obj_id = object.get("id")
                if obj_type in included_cache and obj_id in included_cache[
                        obj_type]:
                    del included_cache[obj_type][obj_id]
                if not included_cache[obj_type]:
                    del included_cache[obj_type]

        if included_cache:
            render_data["included"] = list()
            for included_type in sorted(included_cache.keys()):
                for included_id in sorted(
                        included_cache[included_type].keys()):
                    render_data["included"].append(
                        included_cache[included_type][included_id])

        if json_api_meta:
            render_data["meta"] = utils.format_field_names(json_api_meta)

        return super().render(render_data, accepted_media_type,
                              renderer_context)
    def render(self, data, accepted_media_type=None, renderer_context=None):

        renderer_context = renderer_context or {}

        view = renderer_context.get("view", None)
        request = renderer_context.get("request", None)

        # Get the resource name.
        resource_name = utils.get_resource_name(renderer_context)

        # If this is an error response, skip the rest.
        if resource_name == 'errors':
            return self.render_errors(data, accepted_media_type, renderer_context)

        # if response.status_code is 204 then the data to be rendered must
        # be None
        response = renderer_context.get('response', None)
        if response is not None and response.status_code == 204:
            return super(JSONRenderer, self).render(
                None, accepted_media_type, renderer_context
            )

        from rest_framework_json_api.views import RelationshipView
        if isinstance(view, RelationshipView):
            return self.render_relationship_view(data, accepted_media_type, renderer_context)

        # If `resource_name` is set to None then render default as the dev
        # wants to build the output format manually.
        if resource_name is None or resource_name is False:
            return super(JSONRenderer, self).render(
                data, accepted_media_type, renderer_context
            )

        json_api_data = data
        # initialize json_api_meta with pagination meta or an empty dict
        json_api_meta = data.get('meta', {}) if isinstance(data, dict) else {}
        included_cache = defaultdict(dict)

        if data and 'results' in data:
            serializer_data = data["results"]
        else:
            serializer_data = data

        serializer = getattr(serializer_data, 'serializer', None)

        included_resources = utils.get_included_resources(request, serializer)

        if serializer is not None:

            # Extract root meta for any type of serializer
            json_api_meta.update(self.extract_root_meta(serializer, serializer_data))

            if getattr(serializer, 'many', False):
                json_api_data = list()

                for position in range(len(serializer_data)):
                    resource = serializer_data[position]  # Get current resource
                    resource_instance = serializer.instance[position]  # Get current instance

                    if isinstance(serializer.child, rest_framework_json_api.
                                  serializers.PolymorphicModelSerializer):
                        resource_serializer_class = serializer.child.\
                            get_polymorphic_serializer_for_instance(resource_instance)(
                                context=serializer.child.context
                            )
                    else:
                        resource_serializer_class = serializer.child

                    fields = utils.get_serializer_fields(resource_serializer_class)
                    force_type_resolution = getattr(
                        resource_serializer_class, '_poly_force_type_resolution', False)

                    json_resource_obj = self.build_json_resource_obj(
                        fields, resource, resource_instance, resource_name, force_type_resolution
                    )
                    meta = self.extract_meta(serializer, resource)
                    if meta:
                        json_resource_obj.update({'meta': utils._format_object(meta)})
                    json_api_data.append(json_resource_obj)

                    self.extract_included(
                        fields, resource, resource_instance, included_resources, included_cache
                    )
            else:
                fields = utils.get_serializer_fields(serializer)
                force_type_resolution = getattr(serializer, '_poly_force_type_resolution', False)

                resource_instance = serializer.instance
                json_api_data = self.build_json_resource_obj(
                    fields, serializer_data, resource_instance, resource_name, force_type_resolution
                )

                meta = self.extract_meta(serializer, serializer_data)
                if meta:
                    json_api_data.update({'meta': utils._format_object(meta)})

                self.extract_included(
                    fields, serializer_data, resource_instance, included_resources, included_cache
                )

        # Make sure we render data in a specific order
        render_data = OrderedDict()

        if isinstance(data, dict) and data.get('links'):
            render_data['links'] = data.get('links')

        # format the api root link list
        if view.__class__ and view.__class__.__name__ == 'APIRoot':
            render_data['data'] = None
            render_data['links'] = json_api_data
        else:
            render_data['data'] = json_api_data

        if included_cache:
            if isinstance(json_api_data, list):
                objects = json_api_data
            else:
                objects = [json_api_data]

            for object in objects:
                obj_type = object.get('type')
                obj_id = object.get('id')
                if obj_type in included_cache and \
                   obj_id in included_cache[obj_type]:
                    del included_cache[obj_type][obj_id]
                if not included_cache[obj_type]:
                    del included_cache[obj_type]

        if included_cache:
            render_data['included'] = list()
            for included_type in sorted(included_cache.keys()):
                for included_id in sorted(included_cache[included_type].keys()):
                    render_data['included'].append(included_cache[included_type][included_id])

        if json_api_meta:
            render_data['meta'] = utils._format_object(json_api_meta)

        return super(JSONRenderer, self).render(
            render_data, accepted_media_type, renderer_context
        )
Exemple #15
0
def test_get_resource_name_no_view():
    assert get_resource_name({}) is None
Exemple #16
0
def test_get_resource_name_with_errors(status_code):
    view = APIView()
    context = {"view": view}
    view.response = Response(status=status_code)
    assert "errors" == get_resource_name(context)
Exemple #17
0
    def render(self, data, accepted_media_type=None, renderer_context=None):

        renderer_context = renderer_context or {}

        view = renderer_context.get("view", None)
        request = renderer_context.get("request", None)

        # Get the resource name.
        resource_name = utils.get_resource_name(renderer_context)

        # If this is an error response, skip the rest.
        if resource_name == 'errors':
            return self.render_errors(data, accepted_media_type, renderer_context)

        # if response.status_code is 204 then the data to be rendered must
        # be None
        response = renderer_context.get('response', None)
        if response is not None and response.status_code == 204:
            return super(JSONRenderer, self).render(
                None, accepted_media_type, renderer_context
            )

        from rest_framework_json_api.views import RelationshipView
        if isinstance(view, RelationshipView):
            return self.render_relationship_view(data, accepted_media_type, renderer_context)

        # If `resource_name` is set to None then render default as the dev
        # wants to build the output format manually.
        if resource_name is None or resource_name is False:
            return super(JSONRenderer, self).render(
                data, accepted_media_type, renderer_context
            )

        json_api_data = data
        # initialize json_api_meta with pagination meta or an empty dict
        json_api_meta = data.get('meta', {}) if isinstance(data, dict) else {}
        included_cache = defaultdict(dict)

        if data and 'results' in data:
            serializer_data = data["results"]
        else:
            serializer_data = data

        serializer = getattr(serializer_data, 'serializer', None)

        included_resources = utils.get_included_resources(request, serializer)

        if serializer is not None:

            # Extract root meta for any type of serializer
            json_api_meta.update(self.extract_root_meta(serializer, serializer_data))

            if getattr(serializer, 'many', False):
                json_api_data = list()

                for position in range(len(serializer_data)):
                    resource = serializer_data[position]  # Get current resource
                    resource_instance = serializer.instance[position]  # Get current instance

                    if isinstance(serializer.child, rest_framework_json_api.
                                  serializers.PolymorphicModelSerializer):
                        resource_serializer_class = serializer.child.\
                            get_polymorphic_serializer_for_instance(resource_instance)()
                    else:
                        resource_serializer_class = serializer.child

                    fields = utils.get_serializer_fields(resource_serializer_class)
                    force_type_resolution = getattr(
                        resource_serializer_class, '_poly_force_type_resolution', False)

                    json_resource_obj = self.build_json_resource_obj(
                        fields, resource, resource_instance, resource_name, force_type_resolution
                    )
                    meta = self.extract_meta(serializer, resource)
                    if meta:
                        json_resource_obj.update({'meta': utils.format_keys(meta)})
                    json_api_data.append(json_resource_obj)

                    self.extract_included(
                        fields, resource, resource_instance, included_resources, included_cache
                    )
            else:
                fields = utils.get_serializer_fields(serializer)
                force_type_resolution = getattr(serializer, '_poly_force_type_resolution', False)

                resource_instance = serializer.instance
                json_api_data = self.build_json_resource_obj(
                    fields, serializer_data, resource_instance, resource_name, force_type_resolution
                )

                meta = self.extract_meta(serializer, serializer_data)
                if meta:
                    json_api_data.update({'meta': utils.format_keys(meta)})

                self.extract_included(
                    fields, serializer_data, resource_instance, included_resources, included_cache
                )

        # Make sure we render data in a specific order
        render_data = OrderedDict()

        if isinstance(data, dict) and data.get('links'):
            render_data['links'] = data.get('links')

        # format the api root link list
        if view.__class__ and view.__class__.__name__ == 'APIRoot':
            render_data['data'] = None
            render_data['links'] = json_api_data
        else:
            render_data['data'] = json_api_data

        if included_cache:
            render_data['included'] = list()
            for included_type in sorted(included_cache.keys()):
                for included_id in sorted(included_cache[included_type].keys()):
                    render_data['included'].append(included_cache[included_type][included_id])

        if json_api_meta:
            render_data['meta'] = utils.format_keys(json_api_meta)

        return super(JSONRenderer, self).render(
            render_data, accepted_media_type, renderer_context
        )
Exemple #18
0
    def render(self, data, accepted_media_type=None, renderer_context=None):

        view = renderer_context.get('view', None)
        request = renderer_context.get('request', None)

        # Get the resource name.
        resource_name = utils.get_resource_name(renderer_context)

        # If this is an error response, skip the rest.
        if resource_name == 'errors':
            return self.render_errors(data, accepted_media_type,
                                      renderer_context)

        from rest_framework_json_api.views import RelationshipView
        if isinstance(view, RelationshipView):
            return self.render_relationship_view(data, accepted_media_type,
                                                 renderer_context)

        # If `resource_name` is set to None then render default as the dev
        # wants to build the output format manually.
        if resource_name is None or resource_name is False:
            return super().render(data, accepted_media_type, renderer_context)

        json_api_data = data
        json_api_included = list()
        # initialize json_api_meta with pagination meta or an empty dict
        json_api_meta = data.get('meta', {}) if isinstance(data, dict) else {}

        if data and 'results' in data:
            serializer_data = data['results']
        else:
            serializer_data = data

        serializer = getattr(serializer_data, 'serializer', None)

        included_resources = utils.get_included_resources(request, serializer)

        if serializer is not None:

            # Get the serializer fields
            fields = utils.get_serializer_fields(serializer)

            # Extract root meta for any type of serializer
            json_api_meta.update(
                self.extract_root_meta(serializer, serializer_data))

            if getattr(serializer, 'many', False):
                json_api_data = list()

                for position in range(len(serializer_data)):
                    resource = serializer_data[
                        position]  # Get current resource
                    resource_instance = serializer.instance[
                        position]  # Get current instance

                    json_resource_obj = self.build_json_resource_obj(
                        fields, resource, resource_instance, resource_name)
                    meta = self.extract_meta(serializer, resource)
                    if meta:
                        json_resource_obj.update(
                            {'meta': api_utils.format_keys(meta)})
                    json_api_data.append(json_resource_obj)

                    included = self.extract_included(fields, resource,
                                                     resource_instance,
                                                     included_resources)
                    if included:
                        json_api_included.extend(included)
            else:
                resource_instance = serializer.instance
                json_api_data = self.build_json_resource_obj(
                    fields, serializer_data, resource_instance, resource_name)

                meta = self.extract_meta(serializer, serializer_data)
                if meta:
                    json_api_data.update({'meta': api_utils.format_keys(meta)})

                included = self.extract_included(fields, serializer_data,
                                                 resource_instance,
                                                 included_resources)
                if included:
                    json_api_included.extend(included)

        # Make sure we render data in a specific order
        render_data = OrderedDict()

        if isinstance(data, dict) and data.get('links'):
            render_data['links'] = data.get('links')

        from rest_framework.routers import APIRootView
        # format the api root link list
        if isinstance(view, APIRootView):
            render_data['data'] = None
            render_data['links'] = json_api_data
        else:
            render_data['data'] = json_api_data

        if len(json_api_included) > 0:
            # Iterate through compound documents to remove duplicates
            seen = set()
            unique_compound_documents = list()
            for included_dict in json_api_included:
                type_tuple = tuple(
                    (included_dict['type'], included_dict['id']))
                if type_tuple not in seen:
                    seen.add(type_tuple)
                    unique_compound_documents.append(included_dict)

            # Sort the items by type then by id
            render_data['included'] = sorted(unique_compound_documents,
                                             key=lambda item:
                                             (item['type'], item['id']))

        if json_api_meta:
            render_data['meta'] = api_utils.format_keys(json_api_meta)

        return super().render(render_data, accepted_media_type,
                              renderer_context)
Exemple #19
0
    def render(self, data, accepted_media_type=None, renderer_context=None):
        view = renderer_context.get("view", None)
        request = renderer_context.get("request", None)

        # Get the resource name.
        resource_name = utils.get_resource_name(renderer_context)

        # If this is an error response, skip the rest.
        if resource_name == 'errors':
            return self.render_errors(data, accepted_media_type,
                                      renderer_context)

        # if response.status_code is 204 then the data to be rendered must
        # be None
        response = renderer_context.get('response', None)
        if response is not None and response.status_code == 204:
            return super(JSONRenderer, self).render(None, accepted_media_type,
                                                    renderer_context)

        from rest_framework_json_api.views import RelationshipView
        if isinstance(view, RelationshipView):
            return self.render_relationship_view(data, accepted_media_type,
                                                 renderer_context)

        # If `resource_name` is set to None then render default as the dev
        # wants to build the output format manually.
        if resource_name is None or resource_name is False:
            return super(JSONRenderer, self).render(data, accepted_media_type,
                                                    renderer_context)

        json_api_data = data
        json_api_included = list()
        # initialize json_api_meta with pagination meta or an empty dict
        json_api_meta = data.get('meta', {}) if isinstance(data, dict) else {}
        if json_api_meta:
            meta_pagination = json_api_meta.pop('pagination')
            meta_links = json_api_meta.pop('links')
            meta_pagination.update(meta_links)
            json_api_meta['pagination'] = meta_pagination
        json_api_meta['include'] = []
        json_api_meta['custom'] = []

        if data and 'results' in data:
            serializer_data = data["results"]
        else:
            serializer_data = data

        serializer = getattr(serializer_data, 'serializer', None)

        included_resources = utils.get_included_resources(request, serializer)

        if serializer is not None:

            # Get the serializer fields
            fields = utils.get_serializer_fields(serializer)

            # Determine if resource name must be resolved on each instance (polymorphic serializer)
            force_type_resolution = getattr(serializer,
                                            '_poly_force_type_resolution',
                                            False)

            # Extract root meta for any type of serializer
            json_api_meta.update(
                self.extract_root_meta(serializer, serializer_data))

            if getattr(serializer, 'many', False):
                json_api_data = list()

                for position in range(len(serializer_data)):
                    resource = serializer_data[
                        position]  # Get current resource
                    resource_instance = serializer.instance[
                        position]  # Get current instance

                    json_resource_obj = self.build_json_resource_obj(
                        fields, resource, resource_instance, resource_name,
                        force_type_resolution)
                    meta = self.extract_meta(serializer, resource)
                    if meta:
                        json_resource_obj.update(
                            {'meta': utils.format_keys(meta)})
                    json_api_data.append(json_resource_obj)

                    included = self.extract_included(fields, resource,
                                                     resource_instance,
                                                     included_resources)
                    if included:
                        json_api_included.extend(included)
            else:
                resource_instance = serializer.instance
                json_api_data = self.build_json_resource_obj(
                    fields, serializer_data, resource_instance, resource_name,
                    force_type_resolution)

                meta = self.extract_meta(serializer, serializer_data)
                if meta:
                    json_api_data.update({'meta': utils.format_keys(meta)})

                included = self.extract_included(fields, serializer_data,
                                                 resource_instance,
                                                 included_resources)
                if included:
                    json_api_included.extend(included)

        # Make sure we render data in a specific order
        render_data = OrderedDict()

        if isinstance(data, dict) and data.get('links'):
            render_data['links'] = data.get('links')

        # format the api root link list
        if view.__class__ and view.__class__.__name__ == 'APIRoot':
            render_data['data'] = None
            render_data['links'] = json_api_data
        else:
            render_data['data'] = json_api_data

        if len(json_api_included) > 0:
            # Iterate through compound documents to remove duplicates
            seen = set()
            unique_compound_documents = list()
            for included_dict in json_api_included:
                type_tuple = tuple(
                    (included_dict['type'], included_dict['id']))
                if type_tuple not in seen:
                    seen.add(type_tuple)
                    unique_compound_documents.append(included_dict)

            # Sort the items by type then by id
            render_data['included'] = sorted(unique_compound_documents,
                                             key=lambda item:
                                             (item['type'], item['id']))

        if json_api_meta:
            render_data['meta'] = utils.format_keys(json_api_meta)

        return super(renderers.JSONRenderer,
                     self).render(render_data, accepted_media_type,
                                  renderer_context)
    def parse(self, stream, media_type=None, parser_context=None):
        """Slightly modified to also check DELETE request body data _if_ provided."""

        result = super(parsers.JSONParser, self).parse(
            stream, media_type=media_type, parser_context=parser_context
        )
        if not isinstance(result, dict) or "data" not in result:
            raise ParseError("Received document does not contain primary data")

        data = result.get("data")
        view = parser_context["view"]

        from rest_framework_json_api.views import RelationshipView

        if isinstance(view, RelationshipView):
            # We skip parsing the object as JSONAPI Resource Identifier Object and not a regular
            # Resource Object
            if isinstance(data, list):
                for resource_identifier_object in data:
                    if not (
                        resource_identifier_object.get("id")
                        and resource_identifier_object.get("type")
                    ):
                        raise ParseError(
                            "Received data contains one or more malformed JSONAPI "
                            "Resource Identifier Object(s)"
                        )
            elif not (data.get("id") and data.get("type")):
                raise ParseError(
                    "Received data is not a valid JSONAPI Resource Identifier Object"
                )

            return data

        request = parser_context.get("request")

        # Sanity check
        if not isinstance(data, dict):
            raise ParseError(
                "Received data is not a valid JSONAPI Resource Identifier Object"
            )

        # Check for inconsistencies
        if request.method in ("PUT", "POST", "PATCH", "DELETE"):
            resource_name = utils.get_resource_name(
                parser_context, expand_polymorphic_types=True
            )
            if isinstance(resource_name, str):
                if data.get("type") != resource_name:
                    raise exceptions.Conflict(
                        "The resource object's type ({data_type}) is not the type that "
                        "constitute the collection represented by the endpoint "
                        "({resource_type}).".format(
                            data_type=data.get("type"), resource_type=resource_name
                        )
                    )
            else:
                if data.get("type") not in resource_name:
                    raise exceptions.Conflict(
                        "The resource object's type ({data_type}) is not the type that "
                        "constitute the collection represented by the endpoint "
                        "(one of [{resource_types}]).".format(
                            data_type=data.get("type"),
                            resource_types=", ".join(resource_name),
                        )
                    )
        if not data.get("id") and request.method in ("PATCH", "PUT", "DELETE"):
            raise ParseError(
                "The resource identifier object must contain an 'id' member"
            )

        if request.method in ("PATCH", "PUT", "DELETE"):
            lookup_url_kwarg = getattr(view, "lookup_url_kwarg", None) or getattr(
                view, "lookup_field", None
            )
            if lookup_url_kwarg and str(data.get("id")) != str(
                view.kwargs[lookup_url_kwarg]
            ):
                raise exceptions.Conflict(
                    "The resource object's id ({data_id}) does not match url's "
                    "lookup id ({url_id})".format(
                        data_id=data.get("id"), url_id=view.kwargs[lookup_url_kwarg]
                    )
                )

        # Construct the return data
        serializer_class = getattr(view, "serializer_class", None)
        parsed_data = {"id": data.get("id")} if "id" in data else {}
        # `type` field needs to be allowed in none polymorphic serializers
        if serializer_class is not None:
            if issubclass(serializer_class, serializers.PolymorphicModelSerializer):
                parsed_data["type"] = data.get("type")
        parsed_data.update(self.parse_attributes(data))
        parsed_data.update(self.parse_relationships(data))
        parsed_data.update(self.parse_metadata(result))
        return parsed_data