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))])
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
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)
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) }
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) }
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)) ])
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))])
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
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) }
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 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)
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)
def to_representation(self, instance): return { 'type': 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.kwargs['related_field']) self._resource_name = get_resource_type_from_instance(instance) return self._resource_name
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
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, )
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)
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, )
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)