Skip to content

Commit f55076e

Browse files
committed
Merge pull request #82 from django-json-api/feature/optimization
More optimization - No need to resolve URLs to get IDs
2 parents cc207d7 + 3fa4c9e commit f55076e

File tree

1 file changed

+36
-57
lines changed

1 file changed

+36
-57
lines changed

rest_framework_json_api/utils.py

+36-57
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ def format_relation_name(value, format_type=None):
146146
def build_json_resource_obj(fields, resource, resource_instance, resource_name):
147147
resource_data = [
148148
('type', resource_name),
149-
('id', extract_id(fields, resource)),
149+
('id', encoding.force_text(resource_instance.pk)),
150150
('attributes', extract_attributes(fields, resource)),
151151
]
152152
relationships = extract_relationships(fields, resource, resource_instance)
@@ -186,31 +186,10 @@ def get_related_resource_type(relation):
186186
return format_relation_name(relation_model.__name__)
187187

188188

189-
def extract_id_from_url(url):
190-
http_prefix = url.startswith(('http:', 'https:'))
191-
if http_prefix:
192-
# If needed convert absolute URLs to relative path
193-
data = urlparse(url).path
194-
prefix = urlresolvers.get_script_prefix()
195-
if data.startswith(prefix):
196-
url = '/' + data[len(prefix):]
197-
198-
match = urlresolvers.resolve(url)
199-
return encoding.force_text(match.kwargs['pk'])
200-
201-
202-
def extract_id(fields, resource):
203-
for field_name, field in six.iteritems(fields):
204-
if field_name == 'id':
205-
return encoding.force_text(resource.get(field_name))
206-
if field_name == api_settings.URL_FIELD_NAME:
207-
return extract_id_from_url(resource.get(field_name))
208-
209-
210189
def extract_attributes(fields, resource):
211190
data = OrderedDict()
212191
for field_name, field in six.iteritems(fields):
213-
# ID is always provided in the root of JSON API so remove it from attrs
192+
# ID is always provided in the root of JSON API so remove it from attributes
214193
if field_name == 'id':
215194
continue
216195
# Skip fields with relations
@@ -234,15 +213,21 @@ def extract_relationships(fields, resource, resource_instance):
234213
if not isinstance(field, (RelatedField, ManyRelatedField, BaseSerializer)):
235214
continue
236215

216+
relation_type = get_related_resource_type(field)
217+
relation_instance_or_manager = getattr(resource_instance, field_name)
218+
237219
if isinstance(field, HyperlinkedIdentityField):
238220
# special case for HyperlinkedIdentityField
239221
relation_data = list()
240-
relation_type = get_related_resource_type(field)
241-
relation_manager = getattr(resource_instance, field_name)
222+
242223
# Don't try to query an empty relation
243-
related = relation_manager.all() if relation_manager is not None else list()
244-
for relation in related:
245-
relation_data.append(OrderedDict([('type', relation_type), ('id', relation.pk)]))
224+
relation_queryset = relation_instance_or_manager.all() \
225+
if relation_instance_or_manager is not None else list()
226+
227+
for related_object in relation_queryset:
228+
relation_data.append(
229+
OrderedDict([('type', relation_type), ('id', encoding.force_text(related_object.pk))])
230+
)
246231

247232
data.update({field_name: {
248233
'links': {
@@ -255,27 +240,26 @@ def extract_relationships(fields, resource, resource_instance):
255240
continue
256241

257242
if isinstance(field, (PrimaryKeyRelatedField, HyperlinkedRelatedField)):
258-
relation_type = get_related_resource_type(field)
259-
relation_id = getattr(resource_instance, field_name).pk if resource.get(field_name) else None
243+
relation_id = relation_instance_or_manager.pk if resource.get(field_name) else None
260244

261245
relation_data = {
262-
'data': (OrderedDict([
263-
('type', relation_type), ('id', relation_id)
264-
]) if relation_id is not None else None)
246+
'data': (
247+
OrderedDict([('type', relation_type), ('id', encoding.force_text(relation_id))])
248+
if relation_id is not None else None)
265249
}
266250

267251
relation_data.update(
268252
{'links': {'related': resource.get(field_name)}}
269-
if isinstance(field, HyperlinkedRelatedField) and resource.get(field_name) else {}
253+
if isinstance(field, HyperlinkedRelatedField) and resource.get(field_name) else dict()
270254
)
271255
data.update({field_name: relation_data})
272256
continue
273257

274258
if isinstance(field, ManyRelatedField):
275259
relation_data = list()
276-
relation = field.child_relation
277-
relation_type = get_related_resource_type(relation)
278-
for related_object in getattr(resource_instance, field_name).all():
260+
related_object = field.child_relation
261+
relation_type = get_related_resource_type(related_object)
262+
for related_object in relation_instance_or_manager.all():
279263
relation_data.append(OrderedDict([
280264
('type', relation_type),
281265
('id', encoding.force_text(related_object.pk))
@@ -292,20 +276,20 @@ def extract_relationships(fields, resource, resource_instance):
292276

293277
if isinstance(field, ListSerializer):
294278
relation_data = list()
295-
296279
serializer = field.child
297280
relation_model = serializer.Meta.model
298281
relation_type = format_relation_name(relation_model.__name__)
299282

300-
# Get the serializer fields
301-
serializer_fields = get_serializer_fields(serializer)
302283
serializer_data = resource.get(field_name)
284+
resource_instance_queryset = relation_instance_or_manager.all()
303285
if isinstance(serializer_data, list):
304-
for serializer_resource in serializer_data:
286+
for position in range(len(serializer_data)):
287+
nested_resource_instance = resource_instance_queryset[position]
305288
relation_data.append(
306-
OrderedDict([
307-
('type', relation_type), ('id', extract_id(serializer_fields, serializer_resource))
308-
]))
289+
OrderedDict(
290+
[('type', relation_type), ('id', encoding.force_text(nested_resource_instance.pk))]
291+
)
292+
)
309293

310294
data.update({field_name: {'data': relation_data}})
311295
continue
@@ -314,15 +298,12 @@ def extract_relationships(fields, resource, resource_instance):
314298
relation_model = field.Meta.model
315299
relation_type = format_relation_name(relation_model.__name__)
316300

317-
# Get the serializer fields
318-
serializer_fields = get_serializer_fields(field)
319-
serializer_data = resource.get(field_name)
320301
data.update({
321302
field_name: {
322303
'data': (
323304
OrderedDict([
324305
('type', relation_type),
325-
('id', extract_id(serializer_fields, serializer_data))
306+
('id', encoding.force_text(relation_instance_or_manager.pk))
326307
]) if resource.get(field_name) else None)
327308
}
328309
})
@@ -342,38 +323,36 @@ def extract_included(fields, resource, resource_instance):
342323
if not isinstance(field, BaseSerializer):
343324
continue
344325

345-
if isinstance(field, ListSerializer):
326+
relation_instance_or_manager = getattr(resource_instance, field_name)
327+
relation_queryset = relation_instance_or_manager.all()
328+
serializer_data = resource.get(field_name)
346329

330+
if isinstance(field, ListSerializer):
347331
serializer = field.child
348332
model = serializer.Meta.model
349333
relation_type = format_relation_name(model.__name__)
350334

351335
# Get the serializer fields
352336
serializer_fields = get_serializer_fields(serializer)
353-
serializer_data = resource.get(field_name)
354-
if isinstance(serializer_data, list):
337+
if serializer_data:
355338
for position in range(len(serializer_data)):
356339
serializer_resource = serializer_data[position]
357-
resource_instance_manager = getattr(resource_instance, field_name).all()
358-
nested_resource_instance = resource_instance_manager[position]
340+
nested_resource_instance = relation_queryset[position]
359341
included_data.append(
360342
build_json_resource_obj(
361343
serializer_fields, serializer_resource, nested_resource_instance, relation_type
362344
)
363345
)
364346

365347
if isinstance(field, ModelSerializer):
366-
367348
model = field.Meta.model
368349
relation_type = format_relation_name(model.__name__)
369350

370351
# Get the serializer fields
371352
serializer_fields = get_serializer_fields(field)
372-
serializer_data = resource.get(field_name)
373-
nested_resource_instance = getattr(resource_instance, field_name).all()
374353
if serializer_data:
375354
included_data.append(
376-
build_json_resource_obj(serializer_fields, serializer_data, nested_resource_instance, relation_type)
355+
build_json_resource_obj(serializer_fields, serializer_data, relation_queryset, relation_type)
377356
)
378357

379358
return format_keys(included_data)

0 commit comments

Comments
 (0)