Ejemplo n.º 1
0
 def build_json_resource_obj(cls,
                             fields,
                             resource,
                             resource_instance,
                             resource_name,
                             force_type_resolution=False):
     # Determine type from the instance if the underlying model is polymorphic
     if force_type_resolution:
         resource_name = utils.get_resource_type_from_instance(
             resource_instance)
     resource_data = [
         ('type', resource_name),
         # ('id', encoding.force_text(resource_instance.pk) if resource_instance else None),
         ('attributes', cls.extract_attributes(fields, resource)),
     ]
     relationships = cls.extract_relationships(fields, resource,
                                               resource_instance)
     if relationships:
         resource_data.append(('relationships', relationships))
     # Add 'self' link if field is present and valid
     if api_settings.URL_FIELD_NAME in resource and \
             isinstance(fields[api_settings.URL_FIELD_NAME], relations.RelatedField):
         resource_data.append(('links', {
             'self': resource[api_settings.URL_FIELD_NAME]
         }))
     return OrderedDict(resource_data)
    def to_representation(self, value):
        if getattr(self, 'pk_field', None) is not None:
            pk = self.pk_field.to_representation(value.pk)
        else:
            pk = value.pk

        return OrderedDict([('type', format_relation_name(get_resource_type_from_instance(value))), ('id', str(pk))])
Ejemplo n.º 3
0
    def _to_representation(self, value):
        if getattr(self, 'pk_field', None) is not None:
            pk = self.pk_field.to_representation(value.pk)
        else:
            pk = getattr(value, self.related_link_self_lookup_field)

        resource_type = self.get_resource_type_from_included_serializer()
        if resource_type is None or not self._skip_polymorphic_optimization:
            resource_type = get_resource_type_from_instance(value)

        relation_data = collections.OrderedDict()
        relation_data['type'] = resource_type
        relation_data['id'] = str(pk)

        if self.related_link_self_view_name:
            request = self.context.get('request', None)
            self_kwargs = {
                lookup_field:
                getattr(
                    value, lookup_field
                ) for lookup_field in self.related_link_self_lookup_fields
            }

            self_link = self.get_url(
                'self', self.related_link_self_view_name, self_kwargs, request)
            relation_data['links'] = {'self': self_link}
        return relation_data
Ejemplo n.º 4
0
 def build_json_resource_obj(
     cls,
     fields,
     resource,
     resource_instance,
     resource_name,
     force_type_resolution=False,
 ):
     """
     Builds the resource object (type, id, attributes) and extracts relationships.
     """
     # Determine type from the instance if the underlying model is polymorphic
     if force_type_resolution:
         resource_name = utils.get_resource_type_from_instance(
             resource_instance)
     resource_data = [
         ("type", resource_name),
         (
             "id",
             encoding.force_str(resource_instance.pk)
             if resource_instance else None,
         ),
         ("attributes", cls.extract_attributes(fields, resource)),
     ]
     relationships = cls.extract_relationships(fields, resource,
                                               resource_instance)
     if relationships:
         resource_data.append(("relationships", relationships))
     # Add 'self' link if field is present and valid
     if api_settings.URL_FIELD_NAME in resource and isinstance(
             fields[api_settings.URL_FIELD_NAME], relations.RelatedField):
         resource_data.append(("links", {
             "self": resource[api_settings.URL_FIELD_NAME]
         }))
     return OrderedDict(resource_data)
Ejemplo n.º 5
0
    def to_representation(self, instance):
        if isinstance(instance, RemoteResource):
            return {'type': instance.type, 'id': instance.id}

        return {
            'type': get_resource_type_from_instance(instance),
            'id': str(instance.pk)
        }
Ejemplo n.º 6
0
    def to_representation(self, instance):
        if isinstance(instance, RemoteResource):
            return {'type': instance.type, 'id': instance.id}

        return {
            'type': get_resource_type_from_instance(instance),
            'id': str(instance.pk)
        }
Ejemplo n.º 7
0
    def to_representation(self, value):
        if getattr(self, 'pk_field', None) is not None:
            pk = self.pk_field.to_representation(value.pk)
        else:
            pk = value.pk

        return OrderedDict([
            ('type',
             format_relation_name(get_resource_type_from_instance(value))),
            ('id', str(pk))
        ])
Ejemplo n.º 8
0
    def to_representation(self, value):
        if getattr(self, 'pk_field', None) is not None:
            pk = self.pk_field.to_representation(value.pk)
        else:
            pk = value.pk

        resource_type = self.get_resource_type_from_included_serializer()
        if resource_type is None or not self._skip_polymorphic_optimization:
            resource_type = get_resource_type_from_instance(value)

        return OrderedDict([('type', resource_type), ('id', str(pk))])
    def to_representation(self, value):
        if getattr(self, 'pk_field', None) is not None:
            pk = self.pk_field.to_representation(value.pk)
        else:
            pk = value.pk

        # check to see if this resource has a different resource_name when
        # included and use that name
        resource_type = None
        root = getattr(self.parent, 'parent', self.parent)
        field_name = self.field_name if self.field_name else self.parent.field_name
        if getattr(root, 'included_serializers', None) is not None:
            includes = get_included_serializers(root)
            if field_name in includes.keys():
                resource_type = get_resource_type_from_serializer(includes[field_name])

        resource_type = resource_type if resource_type else get_resource_type_from_instance(value)
        return OrderedDict([('type', resource_type), ('id', str(pk))])
Ejemplo n.º 10
0
    def to_representation(self, value):
        # force pk to be UUID
        pk = getattr(value, 'uuid', getattr(value, 'pk'))

        # check to see if this resource has a different resource_name when
        # included and use that name
        resource_type = None
        root = getattr(self.parent, 'parent', self.parent)
        field_name = self.field_name if self.field_name else self.parent.field_name
        if getattr(root, 'included_serializers', None) is not None:
            includes = get_included_serializers(root)
            if field_name in includes.keys():
                resource_type = get_resource_type_from_serializer(
                    includes[field_name])

        resource_type = resource_type if resource_type else get_resource_type_from_instance(
            value)
        return OrderedDict([('type', resource_type.lower()), ('id', str(pk))])
    def to_representation(self, instance):
        """
        Object instance -> Dict of primitive datatypes.
        """
        ret = OrderedDict()
        readable_fields = [
            field for field in self.fields.values() if not field.write_only
        ]

        for field in readable_fields:
            try:

                if isinstance(field, ModelSerializer) and hasattr(
                        field, field.source + "_id"):
                    attribute = getattr(instance, field.source + "_id")
                    if attribute is None:
                        ret[field.field_name] = None
                        continue
                    resource_type = get_resource_type_from_instance(field)
                    if resource_type:
                        ret[field.field_name] = OrderedDict([
                            ("type", resource_type), ("id", attribute)
                        ])
                        continue

                attribute = field.get_attribute(instance)
            except SkipField:
                continue

            # We skip `to_representation` for `None` values so that fields do
            # not have to explicitly deal with that case.
            #
            # For related fields with `use_pk_only_optimization` we need to
            # resolve the pk value.
            check_for_none = attribute.pk if isinstance(
                attribute, PKOnlyObject) else attribute
            if check_for_none is None:
                ret[field.field_name] = None
            else:
                ret[field.field_name] = field.to_representation(attribute)

        return ret
Ejemplo n.º 12
0
    def to_representation(self, value):
        if getattr(self, 'pk_field', None) is not None:
            pk = self.pk_field.to_representation(value.pk)
        else:
            pk = value.pk

        # check to see if this resource has a different resource_name when
        # included and use that name
        resource_type = None
        root = getattr(self.parent, 'parent', self.parent)
        field_name = self.field_name if self.field_name else self.parent.field_name
        if getattr(root, 'included_serializers', None) is not None:
            includes = get_included_serializers(root)
            if field_name in includes.keys():
                resource_type = get_resource_type_from_serializer(
                    includes[field_name])

        resource_type = resource_type if resource_type else get_resource_type_from_instance(
            value)
        return OrderedDict([('type', resource_type), ('auction', str(pk))])
 def build_json_resource_obj(cls, fields, resource, resource_instance, resource_name,
                             force_type_resolution=False):
     """
     Builds the resource object (type, id, attributes) and extracts relationships.
     """
     # Determine type from the instance if the underlying model is polymorphic
     if force_type_resolution:
         resource_name = utils.get_resource_type_from_instance(resource_instance)
     resource_data = [
         ('type', resource_name),
         ('id', encoding.force_text(resource_instance.pk) if resource_instance else None),
         ('attributes', cls.extract_attributes(fields, resource)),
     ]
     relationships = cls.extract_relationships(fields, resource, resource_instance)
     if relationships:
         resource_data.append(('relationships', relationships))
     # Add 'self' link if field is present and valid
     if api_settings.URL_FIELD_NAME in resource and \
             isinstance(fields[api_settings.URL_FIELD_NAME], relations.RelatedField):
         resource_data.append(('links', {'self': resource[api_settings.URL_FIELD_NAME]}))
     return OrderedDict(resource_data)
 def to_representation(self, instance):
     return {
         "type": get_resource_type_from_instance(instance),
         "id": str(instance.pk),
     }
 def to_representation(self, instance):
     return {
         'type':
         format_relation_name(get_resource_type_from_instance(instance)),
         'id': str(instance.pk)
     }
Ejemplo n.º 16
0
    def extract_relationships(cls, fields, resource, resource_instance):
        # Avoid circular deps
        from rest_framework_json_api.relations import ResourceRelatedField

        data = OrderedDict()

        # Don't try to extract relationships from a non-existent resource
        if resource_instance is None:
            return

        for field_name, field in six.iteritems(fields):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # Skip fields without relations
            if not isinstance(field, (relations.RelatedField, relations.ManyRelatedField, BaseSerializer)):
                continue

            source = field.source
            relation_type = utils.get_related_resource_type(field)

            if isinstance(field, relations.HyperlinkedIdentityField):
                resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
                if not resolved:
                    continue
                # special case for HyperlinkedIdentityField
                relation_data = list()

                # Don't try to query an empty relation
                relation_queryset = relation_instance \
                    if relation_instance is not None else list()

                for related_object in relation_queryset:
                    relation_data.append(
                        OrderedDict([('type', relation_type), ('id', encoding.force_text(related_object.pk))])
                    )

                data.update({field_name: {
                    'links': {
                        'related': resource.get(field_name)},
                    'data': cls.encode_ids(relation_data),
                    'meta': {
                        'count': len(relation_data)
                    }
                }})
                continue

            if isinstance(field, ResourceRelatedField):
                resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
                if not resolved:
                    continue

                # special case for ResourceRelatedField
                relation_data = {
                    'data': cls.encode_ids(resource.get(field_name))
                }

                field_links = field.get_links(resource_instance)
                relation_data.update(
                    {'links': field_links}
                    if field_links else dict()
                )
                data.update({field_name: relation_data})
                continue

            if isinstance(field, (relations.PrimaryKeyRelatedField, relations.HyperlinkedRelatedField)):
                resolved, relation = utils.get_relation_instance(resource_instance, '%s_id' % source, field.parent)
                if not resolved:
                    continue
                relation_id = relation if resource.get(field_name) else None
                relation_data = {
                    'data': (
                        OrderedDict([('type', relation_type), ('id', cls.encode_id(relation_id, relation_type))])
                        if relation_id is not None else None)
                }

                relation_data.update(
                    {'links': {'related': resource.get(field_name)}}
                    if isinstance(field, relations.HyperlinkedRelatedField) and resource.get(field_name) else dict()
                )
                data.update({field_name: relation_data})
                continue

            if isinstance(field, relations.ManyRelatedField):
                resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
                if not resolved:
                    continue

                if isinstance(field.child_relation, ResourceRelatedField):
                    # special case for ResourceRelatedField
                    relation_data = {
                        'data': cls.encode_ids(resource.get(field_name))
                    }

                    field_links = field.child_relation.get_links(resource_instance)
                    relation_data.update(
                        {'links': field_links}
                        if field_links else dict()
                    )
                    relation_data.update(
                        {
                            'meta': {
                                'count': len(resource.get(field_name))
                            }
                        }
                    )
                    data.update({field_name: relation_data})
                    continue

                relation_data = list()
                for nested_resource_instance in relation_instance:
                    nested_resource_instance_type = (
                        relation_type or
                        utils.get_resource_type_from_instance(nested_resource_instance)
                    )

                    relation_data.append(OrderedDict([
                        ('type', nested_resource_instance_type),
                        ('id', encoding.force_text(nested_resource_instance.pk))
                    ]))
                data.update({
                    field_name: {
                        'data': cls.encode_ids(relation_data),
                        'meta': {
                            'count': len(relation_data)
                        }
                    }
                })
                continue

            if isinstance(field, ListSerializer):
                resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
                if not resolved:
                    continue

                relation_data = list()

                serializer_data = resource.get(field_name)
                resource_instance_queryset = list(relation_instance)
                if isinstance(serializer_data, list):
                    for position in range(len(serializer_data)):
                        nested_resource_instance = resource_instance_queryset[position]
                        nested_resource_instance_type = (
                            relation_type or
                            utils.get_resource_type_from_instance(nested_resource_instance)
                        )

                        relation_data.append(OrderedDict([
                            ('type', nested_resource_instance_type),
                            ('id', encoding.force_text(nested_resource_instance.pk))
                        ]))

                    data.update({field_name: {'data': cls.encode_ids(relation_data)}})
                    continue

            if isinstance(field, Serializer):
                resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
                if not resolved:
                    continue

                data.update({
                    field_name: {
                        'data': (
                            OrderedDict([
                                ('type', relation_type),
                                ('id', cls.encode_id(resource_instance.pk, relation_type))
                            ]) if resource.get(field_name) else None)
                    }
                })
                continue

        return utils.format_keys(data)
Ejemplo n.º 17
0
    def extract_included(cls, request, fields, resource, resource_instance,
                         included_resources):
        # this function may be called with an empty record (example: Browsable Interface)
        if not resource_instance:
            return

        included_data = list()
        current_serializer = fields.serializer
        context = current_serializer.context
        included_serializers = utils.get_included_serializers(
            current_serializer)
        included_resources = copy.copy(included_resources)
        included_resources = [
            inflection.underscore(value) for value in included_resources
        ]

        for field_name, field in six.iteritems(fields):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # Skip fields without relations or serialized data
            if not isinstance(field,
                              (relations.RelatedField,
                               relations.ManyRelatedField, BaseSerializer)):
                continue

            try:
                included_resources.remove(field_name)
            except ValueError:
                # Skip fields not in requested included resources
                # If no child field, directly continue with the next field
                if field_name not in [
                        node.split('.')[0] for node in included_resources
                ]:
                    continue

            try:
                relation_instance = getattr(resource_instance, field_name)
            except AttributeError:
                try:
                    # For ManyRelatedFields if `related_name` is not set we need to access `foo_set` from `source`
                    relation_instance = getattr(resource_instance,
                                                field.child_relation.source)
                except AttributeError:
                    if not hasattr(current_serializer, field.source):
                        continue
                    serializer_method = getattr(current_serializer,
                                                field.source)
                    relation_instance = serializer_method(resource_instance)

            if isinstance(relation_instance, Manager):
                relation_instance = relation_instance.all()

            new_included_resources = [
                key.replace('%s.' % field_name, '', 1)
                for key in included_resources
                if field_name == key.split('.')[0]
            ]
            serializer_data = resource.get(field_name)

            if isinstance(field, RemoteResourceField):
                user_id = getattr(request.user, 'id', None)
                roles = request.user.roles
                pk = serializer_data.get('id')

                include = ",".join(new_included_resources)
                try:
                    remote_resource = event_client.get_remote_resource_data(
                        field_name,
                        pk=pk,
                        user_id=user_id,
                        include=include,
                        page_size=1000,
                        roles=roles)

                    body = ujson.loads(remote_resource['body'])

                    if 400 <= remote_resource['status'] < 600:
                        raise RemoteResourceIncludeError(
                            field_name, body["errors"][0])
                except RequestTimeout:
                    raise RemoteResourceIncludeTimeoutError(field_name)

                included_data.append(body['data'])

                if body.get('included'):
                    included_data.extend(body['included'])

                # We continue here since RemoteResourceField inherits
                # form ResourceRelatedField which is a RelatedField
                continue

            if isinstance(field, relations.ManyRelatedField):
                serializer_class = included_serializers[field_name]
                field = serializer_class(relation_instance,
                                         many=True,
                                         context=context)
                serializer_data = field.data

            if isinstance(field, relations.RelatedField):
                if relation_instance is None:
                    continue

                many = field._kwargs.get('child_relation', None) is not None
                serializer_class = included_serializers[field_name]
                field = serializer_class(relation_instance,
                                         many=many,
                                         context=context)
                serializer_data = field.data

            if isinstance(field, ListSerializer):
                serializer = field.child
                relation_type = utils.get_resource_type_from_serializer(
                    serializer)
                relation_queryset = list(relation_instance)

                # Get the serializer fields
                serializer_fields = utils.get_serializer_fields(serializer)
                if serializer_data:
                    for position in range(len(serializer_data)):
                        serializer_resource = serializer_data[position]
                        nested_resource_instance = relation_queryset[position]
                        resource_type = (relation_type or
                                         utils.get_resource_type_from_instance(
                                             nested_resource_instance))
                        included_data.append(
                            cls.build_json_resource_obj(
                                serializer_fields, serializer_resource,
                                nested_resource_instance, resource_type))
                        included_data.extend(
                            cls.extract_included(request, serializer_fields,
                                                 serializer_resource,
                                                 nested_resource_instance,
                                                 new_included_resources))

            if isinstance(field, Serializer):

                relation_type = utils.get_resource_type_from_serializer(field)

                # Get the serializer fields
                serializer_fields = utils.get_serializer_fields(field)
                if serializer_data:
                    included_data.append(
                        cls.build_json_resource_obj(serializer_fields,
                                                    serializer_data,
                                                    relation_instance,
                                                    relation_type))
                    included_data.extend(
                        cls.extract_included(request, serializer_fields,
                                             serializer_data,
                                             relation_instance,
                                             new_included_resources))

        return key_formatter()(included_data)
Ejemplo n.º 18
0
    def extract_relationships(cls, fields, resource, resource_instance):
        """
        Builds the relationships top level object based on related serializers.
        """
        # Avoid circular deps
        from rest_framework_json_api.relations import ResourceRelatedField

        data = OrderedDict()
        render_nested_as_attribute = json_api_settings.SERIALIZE_NESTED_SERIALIZERS_AS_ATTRIBUTE

        # Don't try to extract relationships from a non-existent resource
        if resource_instance is None:
            return

        for field_name, field in iter(fields.items()):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # don't output a key for write only fields
            if fields[field_name].write_only:
                continue

            # Skip fields without relations
            if not isinstance(field,
                              (relations.RelatedField,
                               relations.ManyRelatedField, BaseSerializer)):
                continue

            if isinstance(field,
                          BaseSerializer) and render_nested_as_attribute:
                continue

            source = field.source
            relation_type = utils.get_related_resource_type(field)

            if isinstance(field, relations.HyperlinkedIdentityField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue
                # special case for HyperlinkedIdentityField
                relation_data = list()

                # Don't try to query an empty relation
                relation_queryset = relation_instance \
                    if relation_instance is not None else list()

                for related_object in relation_queryset:
                    relation_data.append(
                        OrderedDict([('type', relation_type),
                                     ('id',
                                      encoding.force_str(related_object.pk))]))

                data.update({
                    field_name: {
                        'links': {
                            "related": resource.get(field_name)
                        },
                        'data': relation_data,
                        'meta': {
                            'count': len(relation_data)
                        }
                    }
                })
                continue

            relation_data = {}
            if isinstance(field, HyperlinkedMixin):
                field_links = field.get_links(resource_instance,
                                              field.related_link_lookup_field)
                relation_data.update(
                    {'links': field_links} if field_links else dict())
                data.update({field_name: relation_data})

            if isinstance(field, (ResourceRelatedField, )):
                if not isinstance(field, SkipDataMixin):
                    relation_data.update({'data': resource.get(field_name)})

                data.update({field_name: relation_data})
                continue

            if isinstance(field, (relations.PrimaryKeyRelatedField,
                                  relations.HyperlinkedRelatedField)):
                resolved, relation = utils.get_relation_instance(
                    resource_instance, '%s_id' % source, field.parent)
                if not resolved:
                    continue
                relation_id = relation if resource.get(field_name) else None
                relation_data = {
                    'data':
                    (OrderedDict([('type', relation_type),
                                  ('id', encoding.force_str(relation_id))])
                     if relation_id is not None else None)
                }

                if (isinstance(field, relations.HyperlinkedRelatedField)
                        and resource.get(field_name)):
                    relation_data.update(
                        {'links': {
                            'related': resource.get(field_name)
                        }})
                data.update({field_name: relation_data})
                continue

            if isinstance(field, relations.ManyRelatedField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue

                relation_data = {}

                if isinstance(resource.get(field_name), Iterable):
                    relation_data.update(
                        {'meta': {
                            'count': len(resource.get(field_name))
                        }})

                if isinstance(field.child_relation, ResourceRelatedField):
                    # special case for ResourceRelatedField
                    relation_data.update({'data': resource.get(field_name)})

                if isinstance(field.child_relation, HyperlinkedMixin):
                    field_links = field.child_relation.get_links(
                        resource_instance,
                        field.child_relation.related_link_lookup_field)
                    relation_data.update(
                        {'links': field_links} if field_links else dict())

                    data.update({field_name: relation_data})
                    continue

                relation_data = list()
                for nested_resource_instance in relation_instance:
                    nested_resource_instance_type = (
                        relation_type or utils.get_resource_type_from_instance(
                            nested_resource_instance))

                    relation_data.append(
                        OrderedDict([
                            ('type', nested_resource_instance_type),
                            ('id',
                             encoding.force_str(nested_resource_instance.pk))
                        ]))
                data.update({
                    field_name: {
                        'data': relation_data,
                        'meta': {
                            'count': len(relation_data)
                        }
                    }
                })
                continue

            if isinstance(field, ListSerializer):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue

                relation_data = list()

                serializer_data = resource.get(field_name)
                resource_instance_queryset = list(relation_instance)
                if isinstance(serializer_data, list):
                    for position in range(len(serializer_data)):
                        nested_resource_instance = resource_instance_queryset[
                            position]
                        nested_resource_instance_type = (
                            relation_type
                            or utils.get_resource_type_from_instance(
                                nested_resource_instance))

                        relation_data.append(
                            OrderedDict([('type',
                                          nested_resource_instance_type),
                                         ('id',
                                          encoding.force_str(
                                              nested_resource_instance.pk))]))

                    data.update({field_name: {'data': relation_data}})
                    continue

            if isinstance(field, Serializer):
                relation_instance_id = getattr(resource_instance,
                                               source + "_id", None)
                if not relation_instance_id:
                    resolved, relation_instance = utils.get_relation_instance(
                        resource_instance, source, field.parent)
                    if not resolved:
                        continue

                    if relation_instance is not None:
                        relation_instance_id = relation_instance.pk

                data.update({
                    field_name: {
                        'data': (OrderedDict([
                            ('type', relation_type),
                            ('id', encoding.force_str(relation_instance_id))
                        ]) if resource.get(field_name) else None)
                    }
                })
                continue

        return utils.format_field_names(data)
Ejemplo n.º 19
0
 def to_representation(self, instance):
     return {
         'type': get_resource_type_from_instance(instance),
         'id': str(instance.pk)
     }
Ejemplo n.º 20
0
 def get_resource_name(self):
     if not hasattr(self, '_resource_name'):
         instance = getattr(self.get_object(), self.kwargs['related_field'])
         self._resource_name = get_resource_type_from_instance(instance)
     return self._resource_name
Ejemplo n.º 21
0
    def extract_relationships(cls, fields, resource, resource_instance):
        # Avoid circular deps
        from rest_framework_json_api.relations import ResourceRelatedField

        data = OrderedDict()

        # Don't try to extract relationships from a non-existent resource
        if resource_instance is None:
            return

        for field_name, field in six.iteritems(fields):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # Skip fields without relations
            if not isinstance(field,
                              (relations.RelatedField,
                               relations.ManyRelatedField, BaseSerializer)):
                continue

            source = field.source
            relation_type = utils.get_related_resource_type(field)

            if isinstance(field, relations.HyperlinkedIdentityField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue
                # special case for HyperlinkedIdentityField
                relation_data = list()

                # Don't try to query an empty relation
                relation_queryset = relation_instance \
                    if relation_instance is not None else list()

                for related_object in relation_queryset:
                    relation_data.append(
                        OrderedDict([
                            ('type', relation_type),
                            ('id', encoding.force_text(related_object.pk))
                        ]))

                data.update({
                    field_name: {
                        'links': {
                            'related': resource.get(field_name)
                        },
                        'data': cls.encode_ids(relation_data),
                        'meta': {
                            'count': len(relation_data)
                        }
                    }
                })
                continue

            if isinstance(field, ResourceRelatedField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue

                # special case for ResourceRelatedField
                relation_data = {
                    'data': cls.encode_ids(resource.get(field_name))
                }

                field_links = field.get_links(resource_instance)
                relation_data.update(
                    {'links': field_links} if field_links else dict())
                data.update({field_name: relation_data})
                continue

            if isinstance(field, (relations.PrimaryKeyRelatedField,
                                  relations.HyperlinkedRelatedField)):
                resolved, relation = utils.get_relation_instance(
                    resource_instance, '%s_id' % source, field.parent)
                if not resolved:
                    continue
                relation_id = relation if resource.get(field_name) else None
                relation_data = {
                    'data': (OrderedDict([
                        ('type', relation_type),
                        ('id', cls.encode_id(relation_id, relation_type))
                    ]) if relation_id is not None else None)
                }

                relation_data.update(
                    {'links': {
                        'related': resource.get(field_name)
                    }} if isinstance(field, relations.HyperlinkedRelatedField)
                    and resource.get(field_name) else dict())
                data.update({field_name: relation_data})
                continue

            if isinstance(field, relations.ManyRelatedField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue

                if isinstance(field.child_relation, ResourceRelatedField):
                    # special case for ResourceRelatedField
                    relation_data = {
                        'data': cls.encode_ids(resource.get(field_name))
                    }

                    field_links = field.child_relation.get_links(
                        resource_instance)
                    relation_data.update(
                        {'links': field_links} if field_links else dict())
                    relation_data.update(
                        {'meta': {
                            'count': len(resource.get(field_name))
                        }})
                    data.update({field_name: relation_data})
                    continue

                relation_data = list()
                for nested_resource_instance in relation_instance:
                    nested_resource_instance_type = (
                        relation_type or utils.get_resource_type_from_instance(
                            nested_resource_instance))

                    relation_data.append(
                        OrderedDict([
                            ('type', nested_resource_instance_type),
                            ('id',
                             encoding.force_text(nested_resource_instance.pk))
                        ]))
                data.update({
                    field_name: {
                        'data': cls.encode_ids(relation_data),
                        'meta': {
                            'count': len(relation_data)
                        }
                    }
                })
                continue

            if isinstance(field, ListSerializer):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue

                relation_data = list()

                serializer_data = resource.get(field_name)
                resource_instance_queryset = list(relation_instance)
                if isinstance(serializer_data, list):
                    for position in range(len(serializer_data)):
                        nested_resource_instance = resource_instance_queryset[
                            position]
                        nested_resource_instance_type = (
                            relation_type
                            or utils.get_resource_type_from_instance(
                                nested_resource_instance))

                        relation_data.append(
                            OrderedDict([('type',
                                          nested_resource_instance_type),
                                         ('id',
                                          encoding.force_text(
                                              nested_resource_instance.pk))]))

                    data.update(
                        {field_name: {
                            'data': cls.encode_ids(relation_data)
                        }})
                    continue

            if isinstance(field, Serializer):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue

                data.update({
                    field_name: {
                        'data':
                        (OrderedDict([('type', relation_type),
                                      ('id',
                                       cls.encode_id(resource_instance.pk,
                                                     relation_type))])
                         if resource.get(field_name) else None)
                    }
                })
                continue

        return utils.format_keys(data)
 def to_representation(self, instance):
     return {
         'type': format_relation_name(get_resource_type_from_instance(instance)),
         'id': str(instance.pk)
     }
 def get_resource_name(self):
     if not hasattr(self, "_resource_name"):
         instance = getattr(self.get_object(),
                            self.get_related_field_name())
         self._resource_name = get_resource_type_from_instance(instance)
     return self._resource_name
Ejemplo n.º 24
0
    def extract_included(cls, fields, resource, resource_instance, included_resources,
                         included_cache):
        """
        Adds related data to the top level included key when the request includes
        ?include=example,example_field2
        """
        # this function may be called with an empty record (example: Browsable Interface)
        if not resource_instance:
            return

        current_serializer = fields.serializer
        context = current_serializer.context
        included_serializers = utils.get_included_serializers(current_serializer)
        included_resources = copy.copy(included_resources)
        included_resources = [inflection.underscore(value) for value in included_resources]

        for field_name, field in six.iteritems(fields):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # Skip fields without relations or serialized data
            if not isinstance(
                    field, (relations.RelatedField, relations.ManyRelatedField, BaseSerializer)
            ):
                continue

            try:
                included_resources.remove(field_name)
            except ValueError:
                # Skip fields not in requested included resources
                # If no child field, directly continue with the next field
                if field_name not in [node.split('.')[0] for node in included_resources]:
                    continue

            relation_instance = cls.extract_relation_instance(
                field, resource_instance
            )
            if isinstance(relation_instance, Manager):
                relation_instance = relation_instance.all()

            serializer_data = resource.get(field_name)

            if isinstance(field, relations.ManyRelatedField):
                serializer_class = included_serializers[field_name]
                context['parent'] = resource_instance
                field = serializer_class(relation_instance, many=True, context=context)
                serializer_data = field.data

            if isinstance(field, relations.RelatedField):
                if relation_instance is None or not serializer_data:
                    continue

                many = field._kwargs.get('child_relation', None) is not None

                if isinstance(field, ResourceRelatedField) and not many:
                    already_included = serializer_data['type'] in included_cache and \
                        serializer_data['id'] in included_cache[serializer_data['type']]

                    if already_included:
                        continue

                serializer_class = included_serializers[field_name]
                context['parent'] = resource_instance
                field = serializer_class(relation_instance, many=many, context=context)
                serializer_data = field.data

            new_included_resources = [key.replace('%s.' % field_name, '', 1)
                                      for key in included_resources
                                      if field_name == key.split('.')[0]]

            if isinstance(field, ListSerializer):
                serializer = field.child
                relation_type = utils.get_resource_type_from_serializer(serializer)
                relation_queryset = list(relation_instance)

                if serializer_data:
                    for position in range(len(serializer_data)):
                        serializer_resource = serializer_data[position]
                        nested_resource_instance = relation_queryset[position]
                        resource_type = (
                            relation_type or
                            utils.get_resource_type_from_instance(nested_resource_instance)
                        )
                        serializer_fields = utils.get_serializer_fields(
                            serializer.__class__(
                                nested_resource_instance, context=serializer.context
                            )
                        )
                        new_item = cls.build_json_resource_obj(
                            serializer_fields,
                            serializer_resource,
                            nested_resource_instance,
                            resource_type,
                            getattr(serializer, '_poly_force_type_resolution', False)
                        )

                        # NEW: Add meta to included resource
                        meta = cls.extract_meta(serializer.__class__, serializer_resource)
                        if meta:
                            new_item.update({'meta': utils._format_object(meta)})

                        included_cache[new_item['type']][new_item['id']] = \
                            utils._format_object(new_item)
                        cls.extract_included(
                            serializer_fields,
                            serializer_resource,
                            nested_resource_instance,
                            new_included_resources,
                            included_cache,
                        )

            if isinstance(field, Serializer):
                relation_type = utils.get_resource_type_from_serializer(field)

                # Get the serializer fields
                serializer_fields = utils.get_serializer_fields(field)
                new_item = cls.build_json_resource_obj(
                    serializer_fields,
                    serializer_data,
                    relation_instance,
                    relation_type,
                    getattr(field, '_poly_force_type_resolution', False)
                )
                # NEW: Add meta to included resource
                meta = cls.extract_meta(serializer_class, serializer_data)
                if meta:
                    new_item.update({'meta': utils._format_object(meta)})

                included_cache[new_item['type']][new_item['id']] = utils._format_object(
                    new_item
                )
                cls.extract_included(
                    serializer_fields,
                    serializer_data,
                    relation_instance,
                    new_included_resources,
                    included_cache,
                )
Ejemplo n.º 25
0
 def get_resource_name(self):
     if not hasattr(self, '_resource_name'):
         instance = getattr(self.get_object(), self.kwargs['related_field'])
         self._resource_name = format_relation_name(get_resource_type_from_instance(instance))
     return self._resource_name
    def extract_relationships(cls, fields, resource, resource_instance):
        """
        Builds the relationships top level object based on related serializers.
        """
        # Avoid circular deps
        from rest_framework_json_api.relations import ResourceRelatedField

        data = OrderedDict()

        # Don't try to extract relationships from a non-existent resource
        if resource_instance is None:
            return

        for field_name, field in six.iteritems(fields):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # don't output a key for write only fields
            if fields[field_name].write_only:
                continue

            # Skip fields without relations
            if not isinstance(
                field, (relations.RelatedField, relations.ManyRelatedField, BaseSerializer)
            ):
                continue

            source = field.source
            relation_type = utils.get_related_resource_type(field)

            if isinstance(field, relations.HyperlinkedIdentityField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent
                )
                if not resolved:
                    continue
                # special case for HyperlinkedIdentityField
                relation_data = list()

                # Don't try to query an empty relation
                relation_queryset = relation_instance \
                    if relation_instance is not None else list()

                for related_object in relation_queryset:
                    relation_data.append(
                        OrderedDict([
                            ('type', relation_type),
                            ('id', encoding.force_text(related_object.pk))
                        ])
                    )

                data.update({field_name: {
                    'links': {
                        "related": resource.get(field_name)},
                    'data': relation_data,
                    'meta': {
                        'count': len(relation_data)
                    }
                }})
                continue

            relation_data = {}
            if isinstance(field, HyperlinkedMixin):
                field_links = field.get_links(resource_instance, field.related_link_lookup_field)
                relation_data.update({'links': field_links} if field_links else dict())
                data.update({field_name: relation_data})

            if isinstance(field, (ResourceRelatedField, )):
                if not isinstance(field, SkipDataMixin):
                    relation_data.update({'data': resource.get(field_name)})

                data.update({field_name: relation_data})
                continue

            if isinstance(
                    field, (relations.PrimaryKeyRelatedField, relations.HyperlinkedRelatedField)
            ):
                resolved, relation = utils.get_relation_instance(
                    resource_instance, '%s_id' % source, field.parent
                )
                if not resolved:
                    continue
                relation_id = relation if resource.get(field_name) else None
                relation_data = {
                    'data': (
                        OrderedDict([
                            ('type', relation_type), ('id', encoding.force_text(relation_id))
                        ])
                        if relation_id is not None else None)
                }

                if (
                    isinstance(field, relations.HyperlinkedRelatedField) and
                    resource.get(field_name)
                ):
                    relation_data.update(
                        {
                            'links': {
                                'related': resource.get(field_name)
                            }
                        }
                    )
                data.update({field_name: relation_data})
                continue

            if isinstance(field, relations.ManyRelatedField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent
                )
                if not resolved:
                    continue

                relation_data = {}

                if isinstance(resource.get(field_name), collections_abc.Iterable):
                    relation_data.update(
                        {
                            'meta': {'count': len(resource.get(field_name))}
                        }
                    )

                if isinstance(field.child_relation, ResourceRelatedField):
                    # special case for ResourceRelatedField
                    relation_data.update(
                        {'data': resource.get(field_name)}
                    )

                if isinstance(field.child_relation, HyperlinkedMixin):
                    field_links = field.child_relation.get_links(
                        resource_instance,
                        field.child_relation.related_link_lookup_field
                    )
                    relation_data.update(
                        {'links': field_links}
                        if field_links else dict()
                    )

                    data.update({field_name: relation_data})
                    continue

                relation_data = list()
                for nested_resource_instance in relation_instance:
                    nested_resource_instance_type = (
                        relation_type or
                        utils.get_resource_type_from_instance(nested_resource_instance)
                    )

                    relation_data.append(OrderedDict([
                        ('type', nested_resource_instance_type),
                        ('id', encoding.force_text(nested_resource_instance.pk))
                    ]))
                data.update({
                    field_name: {
                        'data': relation_data,
                        'meta': {
                            'count': len(relation_data)
                        }
                    }
                })
                continue

            if isinstance(field, ListSerializer):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent
                )
                if not resolved:
                    continue

                relation_data = list()

                serializer_data = resource.get(field_name)
                resource_instance_queryset = list(relation_instance)
                if isinstance(serializer_data, list):
                    for position in range(len(serializer_data)):
                        nested_resource_instance = resource_instance_queryset[position]
                        nested_resource_instance_type = (
                            relation_type or
                            utils.get_resource_type_from_instance(nested_resource_instance)
                        )

                        relation_data.append(OrderedDict([
                            ('type', nested_resource_instance_type),
                            ('id', encoding.force_text(nested_resource_instance.pk))
                        ]))

                    data.update({field_name: {'data': relation_data}})
                    continue

            if isinstance(field, Serializer):
                relation_instance_id = getattr(resource_instance, source + "_id", None)
                if not relation_instance_id:
                    resolved, relation_instance = utils.get_relation_instance(
                        resource_instance, source, field.parent
                    )
                    if not resolved:
                        continue

                    if relation_instance is not None:
                        relation_instance_id = relation_instance.pk

                data.update({
                    field_name: {
                        'data': (
                            OrderedDict([
                                ('type', relation_type),
                                ('id', encoding.force_text(relation_instance_id))
                            ]) if resource.get(field_name) else None)
                    }
                })
                continue

        return utils._format_object(data)
Ejemplo n.º 27
0
 def to_representation(self, instance):
     return {
         'type': get_resource_type_from_instance(instance),
         'id': str(instance.pk)
     }
    def extract_relationships(cls, fields, resource, resource_instance):
        """
        Builds the relationships top level object based on related serializers.
        """
        # Avoid circular deps
        from rest_framework_json_api.relations import ResourceRelatedField

        data = OrderedDict()

        # Don't try to extract relationships from a non-existent resource
        if resource_instance is None:
            return

        for field_name, field in iter(fields.items()):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # don't output a key for write only fields
            if fields[field_name].write_only:
                continue

            # Skip fields without relations
            if not utils.is_relationship_field(field):
                continue

            source = field.source
            relation_type = utils.get_related_resource_type(field)

            if isinstance(field, relations.HyperlinkedIdentityField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue
                # special case for HyperlinkedIdentityField
                relation_data = list()

                # Don't try to query an empty relation
                relation_queryset = (relation_instance if relation_instance
                                     is not None else list())

                for related_object in relation_queryset:
                    relation_data.append(
                        OrderedDict([
                            ("type", relation_type),
                            ("id", encoding.force_str(related_object.pk)),
                        ]))

                data.update({
                    field_name: {
                        "links": {
                            "related": resource.get(field_name)
                        },
                        "data": relation_data,
                        "meta": {
                            "count": len(relation_data)
                        },
                    }
                })
                continue

            relation_data = {}
            if isinstance(field, HyperlinkedMixin):
                field_links = field.get_links(resource_instance,
                                              field.related_link_lookup_field)
                relation_data.update(
                    {"links": field_links} if field_links else dict())
                data.update({field_name: relation_data})

            if isinstance(field, (ResourceRelatedField, )):
                if not isinstance(field, SkipDataMixin):
                    relation_data.update({"data": resource.get(field_name)})

                data.update({field_name: relation_data})
                continue

            if isinstance(
                    field,
                (relations.PrimaryKeyRelatedField,
                 relations.HyperlinkedRelatedField),
            ):
                resolved, relation = utils.get_relation_instance(
                    resource_instance, "%s_id" % source, field.parent)
                if not resolved:
                    continue
                relation_id = relation if resource.get(field_name) else None
                relation_data = {
                    "data": (OrderedDict([
                        ("type", relation_type),
                        ("id", encoding.force_str(relation_id)),
                    ]) if relation_id is not None else None)
                }

                if isinstance(field, relations.HyperlinkedRelatedField
                              ) and resource.get(field_name):
                    relation_data.update(
                        {"links": {
                            "related": resource.get(field_name)
                        }})
                data.update({field_name: relation_data})
                continue

            if isinstance(field, relations.ManyRelatedField):
                resolved, relation_instance = utils.get_relation_instance(
                    resource_instance, source, field.parent)
                if not resolved:
                    continue

                relation_data = {}

                if isinstance(resource.get(field_name), Iterable):
                    relation_data.update(
                        {"meta": {
                            "count": len(resource.get(field_name))
                        }})

                if isinstance(field.child_relation, ResourceRelatedField):
                    # special case for ResourceRelatedField
                    relation_data.update({"data": resource.get(field_name)})

                if isinstance(field.child_relation, HyperlinkedMixin):
                    field_links = field.child_relation.get_links(
                        resource_instance,
                        field.child_relation.related_link_lookup_field,
                    )
                    relation_data.update(
                        {"links": field_links} if field_links else dict())

                    data.update({field_name: relation_data})
                    continue

                relation_data = list()
                for nested_resource_instance in relation_instance:
                    nested_resource_instance_type = (
                        relation_type or utils.get_resource_type_from_instance(
                            nested_resource_instance))

                    relation_data.append(
                        OrderedDict([
                            ("type", nested_resource_instance_type),
                            ("id",
                             encoding.force_str(nested_resource_instance.pk)),
                        ]))
                data.update({
                    field_name: {
                        "data": relation_data,
                        "meta": {
                            "count": len(relation_data)
                        },
                    }
                })
                continue

        return utils.format_field_names(data)
    def extract_included(cls, fields, resource, resource_instance,
                         included_resources, included_cache):
        """
        Adds related data to the top level included key when the request includes
        ?include=example,example_field2
        """
        # this function may be called with an empty record (example: Browsable Interface)
        if not resource_instance:
            return

        current_serializer = fields.serializer
        context = current_serializer.context
        included_serializers = getattr(current_serializer,
                                       "included_serializers", dict())
        included_resources = copy.copy(included_resources)
        included_resources = [
            inflection.underscore(value) for value in included_resources
        ]

        for field_name, field in iter(fields.items()):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # Skip fields without relations
            if not utils.is_relationship_field(field):
                continue

            try:
                included_resources.remove(field_name)
            except ValueError:
                # Skip fields not in requested included resources
                # If no child field, directly continue with the next field
                if field_name not in [
                        node.split(".")[0] for node in included_resources
                ]:
                    continue

            relation_instance = cls.extract_relation_instance(
                field, resource_instance)
            if isinstance(relation_instance, Manager):
                relation_instance = relation_instance.all()

            serializer_data = resource.get(field_name)

            if isinstance(field, relations.ManyRelatedField):
                serializer_class = included_serializers[field_name]
                field = serializer_class(relation_instance,
                                         many=True,
                                         context=context)
                serializer_data = field.data

            if isinstance(field, relations.RelatedField):
                if relation_instance is None or not serializer_data:
                    continue

                many = field._kwargs.get("child_relation", None) is not None

                if isinstance(field, ResourceRelatedField) and not many:
                    already_included = (
                        serializer_data["type"] in included_cache
                        and serializer_data["id"]
                        in included_cache[serializer_data["type"]])

                    if already_included:
                        continue

                serializer_class = included_serializers[field_name]
                field = serializer_class(relation_instance,
                                         many=many,
                                         context=context)
                serializer_data = field.data

            new_included_resources = [
                key.replace("%s." % field_name, "", 1)
                for key in included_resources
                if field_name == key.split(".")[0]
            ]

            if isinstance(field, ListSerializer):
                serializer = field.child
                relation_type = utils.get_resource_type_from_serializer(
                    serializer)
                relation_queryset = list(relation_instance)

                if serializer_data:
                    for position in range(len(serializer_data)):
                        serializer_resource = serializer_data[position]
                        nested_resource_instance = relation_queryset[position]
                        resource_type = (relation_type or
                                         utils.get_resource_type_from_instance(
                                             nested_resource_instance))
                        serializer_fields = utils.get_serializer_fields(
                            serializer.__class__(nested_resource_instance,
                                                 context=serializer.context))
                        new_item = cls.build_json_resource_obj(
                            serializer_fields,
                            serializer_resource,
                            nested_resource_instance,
                            resource_type,
                            serializer,
                            getattr(serializer, "_poly_force_type_resolution",
                                    False),
                        )
                        included_cache[new_item["type"]][
                            new_item["id"]] = new_item

                        cls.extract_included(
                            serializer_fields,
                            serializer_resource,
                            nested_resource_instance,
                            new_included_resources,
                            included_cache,
                        )

            if isinstance(field, Serializer):
                relation_type = utils.get_resource_type_from_serializer(field)

                # Get the serializer fields
                serializer_fields = utils.get_serializer_fields(field)
                if serializer_data:
                    new_item = cls.build_json_resource_obj(
                        serializer_fields,
                        serializer_data,
                        relation_instance,
                        relation_type,
                        field,
                        getattr(field, "_poly_force_type_resolution", False),
                    )
                    included_cache[new_item["type"]][new_item["id"]] = new_item

                    cls.extract_included(
                        serializer_fields,
                        serializer_data,
                        relation_instance,
                        new_included_resources,
                        included_cache,
                    )
 def get_resource_name(self):
     if not hasattr(self, '_resource_name'):
         instance = getattr(self.get_object(), self.get_related_field_name())
         self._resource_name = get_resource_type_from_instance(instance)
     return self._resource_name
    def extract_included(cls, fields, resource, resource_instance, included_resources,
                         included_cache):
        """
        Adds related data to the top level included key when the request includes
        ?include=example,example_field2
        """
        # this function may be called with an empty record (example: Browsable Interface)
        if not resource_instance:
            return

        current_serializer = fields.serializer
        context = current_serializer.context
        included_serializers = utils.get_included_serializers(current_serializer)
        included_resources = copy.copy(included_resources)
        included_resources = [inflection.underscore(value) for value in included_resources]

        for field_name, field in six.iteritems(fields):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # Skip fields without relations or serialized data
            if not isinstance(
                    field, (relations.RelatedField, relations.ManyRelatedField, BaseSerializer)
            ):
                continue

            try:
                included_resources.remove(field_name)
            except ValueError:
                # Skip fields not in requested included resources
                # If no child field, directly continue with the next field
                if field_name not in [node.split('.')[0] for node in included_resources]:
                    continue

            relation_instance = cls.extract_relation_instance(
                field_name, field, resource_instance, current_serializer
            )
            if isinstance(relation_instance, Manager):
                relation_instance = relation_instance.all()

            serializer_data = resource.get(field_name)

            if isinstance(field, relations.ManyRelatedField):
                serializer_class = included_serializers[field_name]
                field = serializer_class(relation_instance, many=True, context=context)
                serializer_data = field.data

            if isinstance(field, relations.RelatedField):
                if relation_instance is None or not serializer_data:
                    continue

                many = field._kwargs.get('child_relation', None) is not None

                if isinstance(field, ResourceRelatedField) and not many:
                    already_included = serializer_data['type'] in included_cache and \
                        serializer_data['id'] in included_cache[serializer_data['type']]

                    if already_included:
                        continue

                serializer_class = included_serializers[field_name]
                field = serializer_class(relation_instance, many=many, context=context)
                serializer_data = field.data

            new_included_resources = [key.replace('%s.' % field_name, '', 1)
                                      for key in included_resources
                                      if field_name == key.split('.')[0]]

            if isinstance(field, ListSerializer):
                serializer = field.child
                relation_type = utils.get_resource_type_from_serializer(serializer)
                relation_queryset = list(relation_instance)

                if serializer_data:
                    for position in range(len(serializer_data)):
                        serializer_resource = serializer_data[position]
                        nested_resource_instance = relation_queryset[position]
                        resource_type = (
                            relation_type or
                            utils.get_resource_type_from_instance(nested_resource_instance)
                        )
                        serializer_fields = utils.get_serializer_fields(
                            serializer.__class__(
                                nested_resource_instance, context=serializer.context
                            )
                        )
                        new_item = cls.build_json_resource_obj(
                            serializer_fields,
                            serializer_resource,
                            nested_resource_instance,
                            resource_type,
                            getattr(serializer, '_poly_force_type_resolution', False)
                        )
                        included_cache[new_item['type']][new_item['id']] = \
                            utils._format_object(new_item)
                        cls.extract_included(
                            serializer_fields,
                            serializer_resource,
                            nested_resource_instance,
                            new_included_resources,
                            included_cache,
                        )

            if isinstance(field, Serializer):
                relation_type = utils.get_resource_type_from_serializer(field)

                # Get the serializer fields
                serializer_fields = utils.get_serializer_fields(field)
                if serializer_data:
                    new_item = cls.build_json_resource_obj(
                        serializer_fields,
                        serializer_data,
                        relation_instance,
                        relation_type,
                        getattr(field, '_poly_force_type_resolution', False)
                    )
                    included_cache[new_item['type']][new_item['id']] = utils._format_object(
                        new_item
                    )
                    cls.extract_included(
                        serializer_fields,
                        serializer_data,
                        relation_instance,
                        new_included_resources,
                        included_cache,
                    )
Ejemplo n.º 32
0
    def extract_included(cls, fields, resource, resource_instance,
                         included_resources):
        # this function may be called with an empty record (example: Browsable Interface)
        if not resource_instance:
            return

        included_data = list()
        current_serializer = fields.serializer
        context = current_serializer.context
        included_serializers = utils.get_included_serializers(
            current_serializer)
        included_resources = copy.copy(included_resources)
        included_resources = [
            inflection.underscore(value) for value in included_resources
        ]

        for field_name, field in six.iteritems(fields):
            # Skip URL field
            if field_name == api_settings.URL_FIELD_NAME:
                continue

            # Skip fields without relations or serialized data
            if not isinstance(field,
                              (relations.RelatedField,
                               relations.ManyRelatedField, BaseSerializer)):
                continue

            try:
                included_resources.remove(field_name)
            except ValueError:
                # Skip fields not in requested included resources
                # If no child field, directly continue with the next field
                if field_name not in [
                        node.split('.')[0] for node in included_resources
                ]:
                    continue

            try:
                relation_instance = getattr(resource_instance, field_name)
            except AttributeError:
                try:
                    # For ManyRelatedFields if `related_name` is not set we need to access `foo_set` from `source`
                    relation_instance = getattr(resource_instance,
                                                field.child_relation.source)
                except AttributeError:
                    if not hasattr(current_serializer, field.source):
                        continue
                    serializer_method = getattr(current_serializer,
                                                field.source)
                    relation_instance = serializer_method(resource_instance)

            if isinstance(relation_instance, Manager):
                relation_instance = relation_instance.all()

            new_included_resources = [
                key.replace('%s.' % field_name, '', 1)
                for key in included_resources
                if field_name == key.split('.')[0]
            ]
            serializer_data = resource.get(field_name)

            if isinstance(field, relations.ManyRelatedField):
                serializer_class = included_serializers[field_name]
                field = serializer_class(relation_instance,
                                         many=True,
                                         context=context)
                serializer_data = field.data

            if isinstance(field, relations.RelatedField):
                if relation_instance is None:
                    continue

                many = field._kwargs.get('child_relation', None) is not None
                serializer_class = included_serializers[field_name]
                field = serializer_class(relation_instance,
                                         many=many,
                                         context=context)
                serializer_data = field.data

            if isinstance(field, ListSerializer):
                serializer = field.child
                relation_type = utils.get_resource_type_from_serializer(
                    serializer)
                relation_queryset = list(relation_instance)

                # Get the serializer fields
                serializer_fields = utils.get_serializer_fields(serializer)
                if serializer_data:
                    for position in range(len(serializer_data)):
                        serializer_resource = serializer_data[position]
                        nested_resource_instance = relation_queryset[position]
                        resource_type = (relation_type or
                                         utils.get_resource_type_from_instance(
                                             nested_resource_instance))
                        included_data.append(
                            cls.build_json_resource_obj(
                                serializer_fields, serializer_resource,
                                nested_resource_instance, resource_type))
                        included_data.extend(
                            cls.extract_included(serializer_fields,
                                                 serializer_resource,
                                                 nested_resource_instance,
                                                 new_included_resources))

            if isinstance(field, Serializer):

                relation_type = utils.get_resource_type_from_serializer(field)

                # Get the serializer fields
                serializer_fields = utils.get_serializer_fields(field)
                if serializer_data:
                    included_data.append(
                        cls.build_json_resource_obj(serializer_fields,
                                                    serializer_data,
                                                    relation_instance,
                                                    relation_type))
                    included_data.extend(
                        cls.extract_included(serializer_fields,
                                             serializer_data,
                                             relation_instance,
                                             new_included_resources))

        return api_utils.format_keys(included_data)