diff --git a/rest_framework_json_api/renderers.py b/rest_framework_json_api/renderers.py index 1c74ffdf..ab50a915 100644 --- a/rest_framework_json_api/renderers.py +++ b/rest_framework_json_api/renderers.py @@ -111,7 +111,8 @@ def extract_relationships(cls, fields, resource, resource_instance): relation_data.append( OrderedDict([ ('type', relation_type), - ('id', encoding.force_text(related_object.pk)) + ('id', encoding.force_text(getattr( + related_object, field.lookup_field))) ]) ) @@ -150,18 +151,24 @@ def extract_relationships(cls, fields, resource, resource_instance): 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 + lookup_field = getattr(field, 'lookup_field', None) + if lookup_field: + relation_id = getattr( + getattr(resource_instance, source), + lookup_field, None) + else: + 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 relation_id is not None else {'data': None}) } if ( @@ -216,9 +223,15 @@ def extract_relationships(cls, fields, resource, resource_instance): utils.get_resource_type_from_instance(nested_resource_instance) ) + if hasattr(field.child_relation, 'lookup_field'): + pk = getattr(nested_resource_instance, + field.child_relation.lookup_field) + else: + pk = nested_resource_instance.pk + relation_data.append(OrderedDict([ ('type', nested_resource_instance_type), - ('id', encoding.force_text(nested_resource_instance.pk)) + ('id', encoding.force_text(pk)) ])) data.update({ field_name: { @@ -244,14 +257,23 @@ def extract_relationships(cls, fields, resource, resource_instance): if isinstance(serializer_data, list): for position in range(len(serializer_data)): nested_resource_instance = resource_instance_queryset[position] + nested_resource_data = serializer_data[position] nested_resource_instance_type = ( relation_type or utils.get_resource_type_from_instance(nested_resource_instance) ) + instance_pk_name = ( + getattr(field, 'lookup_field', None) or + nested_resource_instance._meta.pk.name) + if instance_pk_name in nested_resource_data: + pk = nested_resource_data[instance_pk_name] + else: + pk = nested_resource_instance.pk + relation_data.append(OrderedDict([ ('type', nested_resource_instance_type), - ('id', encoding.force_text(nested_resource_instance.pk)) + ('id', encoding.force_text(pk)) ])) data.update({field_name: {'data': relation_data}}) @@ -463,9 +485,19 @@ def build_json_resource_obj(cls, fields, resource, resource_instance, resource_n # 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) + if resource_instance is None: + pk = None + elif 'id' in fields: + pk = fields['id'].get_attribute(resource_instance) + elif 'url' in fields: + pk = getattr(resource_instance, fields['url'].lookup_field) + else: + # Check if the primary key exists in the resource by getting the + # primary keys attribute name. + pk = resource_instance.pk resource_data = [ ('type', resource_name), - ('id', encoding.force_text(resource_instance.pk) if resource_instance else None), + ('id', encoding.force_text(pk)), ('attributes', cls.extract_attributes(fields, resource)), ] relationships = cls.extract_relationships(fields, resource, resource_instance)