Skip to content

Commit 10f818e

Browse files
committed
Merge remote-tracking branch 'orf/alternate-pk' into develop
2 parents f0fa0e7 + d9e1196 commit 10f818e

File tree

2 files changed

+37
-8
lines changed

2 files changed

+37
-8
lines changed

rest_framework_json_api/renderers.py

+32-6
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,15 @@ def extract_relationships(cls, fields, resource, resource_instance):
9090
source = field.source
9191
relation_type = utils.get_related_resource_type(field)
9292

93+
# Take a model and return it's primary key, calling the primary key fields 'get_attribute'
94+
# function or the models .pk property.
95+
def get_pk(obj):
96+
pk_attr = obj._meta.pk.name
97+
if hasattr(field, 'fields') and pk_attr in field.fields:
98+
return field.fields[pk_attr].get_attribute(obj)
99+
else:
100+
return obj.pk
101+
93102
if isinstance(field, relations.HyperlinkedIdentityField):
94103
resolved, relation_instance = utils.get_relation_instance(resource_instance, source, field.parent)
95104
if not resolved:
@@ -103,7 +112,7 @@ def extract_relationships(cls, fields, resource, resource_instance):
103112

104113
for related_object in relation_queryset:
105114
relation_data.append(
106-
OrderedDict([('type', relation_type), ('id', encoding.force_text(related_object.pk))])
115+
OrderedDict([('type', relation_type), ('id', encoding.force_text(get_pk(related_object)))])
107116
)
108117

109118
data.update({field_name: {
@@ -138,7 +147,9 @@ def extract_relationships(cls, fields, resource, resource_instance):
138147
resolved, relation = utils.get_relation_instance(resource_instance, '%s_id' % source, field.parent)
139148
if not resolved:
140149
continue
141-
relation_id = relation if resource.get(field_name) else None
150+
relation_id = get_pk(
151+
getattr(resource_instance, source)
152+
) if resource.get(field_name) else None
142153
relation_data = {
143154
'data': (
144155
OrderedDict([('type', relation_type), ('id', encoding.force_text(relation_id))])
@@ -187,7 +198,7 @@ def extract_relationships(cls, fields, resource, resource_instance):
187198

188199
relation_data.append(OrderedDict([
189200
('type', nested_resource_instance_type),
190-
('id', encoding.force_text(nested_resource_instance.pk))
201+
('id', encoding.force_text(get_pk(nested_resource_instance)))
191202
]))
192203
data.update({
193204
field_name: {
@@ -211,14 +222,21 @@ def extract_relationships(cls, fields, resource, resource_instance):
211222
if isinstance(serializer_data, list):
212223
for position in range(len(serializer_data)):
213224
nested_resource_instance = resource_instance_queryset[position]
225+
nested_resource_data = serializer_data[position]
214226
nested_resource_instance_type = (
215227
relation_type or
216228
utils.get_resource_type_from_instance(nested_resource_instance)
217229
)
218230

231+
instance_pk_name = nested_resource_instance._meta.pk.name
232+
if instance_pk_name in nested_resource_data:
233+
pk = nested_resource_data[instance_pk_name]
234+
else:
235+
pk = nested_resource_instance.pk
236+
219237
relation_data.append(OrderedDict([
220238
('type', nested_resource_instance_type),
221-
('id', encoding.force_text(nested_resource_instance.pk))
239+
('id', encoding.force_text(pk))
222240
]))
223241

224242
data.update({field_name: {'data': relation_data}})
@@ -234,7 +252,7 @@ def extract_relationships(cls, fields, resource, resource_instance):
234252
'data': (
235253
OrderedDict([
236254
('type', relation_type),
237-
('id', encoding.force_text(relation_instance.pk))
255+
('id', get_pk(relation_instance))
238256
]) if resource.get(field_name) else None)
239257
}
240258
})
@@ -382,9 +400,17 @@ def extract_root_meta(cls, serializer, resource):
382400

383401
@classmethod
384402
def build_json_resource_obj(cls, fields, resource, resource_instance, resource_name):
403+
if resource_instance is None:
404+
pk = None
405+
else:
406+
# Check if the primary key exists in the resource by getting the primary keys attribute name.
407+
pk_attr = resource_instance._meta.pk.name
408+
pk = resource[pk_attr] if pk_attr in resource else resource_instance.pk
409+
pk = encoding.force_text(pk)
410+
385411
resource_data = [
386412
('type', resource_name),
387-
('id', encoding.force_text(resource_instance.pk) if resource_instance else None),
413+
('id', pk),
388414
('attributes', cls.extract_attributes(fields, resource)),
389415
]
390416
relationships = cls.extract_relationships(fields, resource, resource_instance)

rest_framework_json_api/serializers.py

+5-2
Original file line numberDiff line numberDiff line change
@@ -17,25 +17,28 @@ class ResourceIdentifierObjectSerializer(BaseSerializer):
1717
}
1818

1919
model_class = None
20+
pk_field = 'pk'
2021

2122
def __init__(self, *args, **kwargs):
2223
self.model_class = kwargs.pop('model_class', self.model_class)
24+
self.pk_field = kwargs.pop('pk_field', self.pk_field)
2325
if 'instance' not in kwargs and not self.model_class:
2426
raise RuntimeError('ResourceIdentifierObjectsSerializer must be initialized with a model class.')
2527
super(ResourceIdentifierObjectSerializer, self).__init__(*args, **kwargs)
2628

2729
def to_representation(self, instance):
2830
return {
2931
'type': get_resource_type_from_instance(instance),
30-
'id': str(instance.pk)
32+
'id': str(getattr(instance, self.pk_field))
3133
}
3234

3335
def to_internal_value(self, data):
3436
if data['type'] != get_resource_type_from_model(self.model_class):
3537
self.fail('incorrect_model_type', model_type=self.model_class, received_type=data['type'])
3638
pk = data['id']
39+
lookup = {self.pk_field: pk}
3740
try:
38-
return self.model_class.objects.get(pk=pk)
41+
return self.model_class.objects.get(**lookup)
3942
except ObjectDoesNotExist:
4043
self.fail('does_not_exist', pk_value=pk)
4144
except (TypeError, ValueError):

0 commit comments

Comments
 (0)