Skip to content

Commit ad4caaf

Browse files
committed
Merge branch 'develop' of github.com:django-json-api/django-rest-framework-json-api into feature/optimization
Working late is bad - forgot to pull before starting to work :(N
2 parents d122fa3 + d997b0b commit ad4caaf

File tree

3 files changed

+73
-40
lines changed

3 files changed

+73
-40
lines changed

rest_framework_json_api/exceptions.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,13 @@ def exception_handler(exc, context):
2929
# see if they passed a dictionary to ValidationError manually
3030
if isinstance(error, dict):
3131
errors.append(error)
32-
else:
32+
# or a string in case of AuthenticationError
33+
elif isinstance(error, str):
34+
# An error MUST be a JSON object in JSON API spec
35+
errors.append({
36+
'detail': error
37+
})
38+
elif isinstance(error, list):
3339
for message in error:
3440
errors.append({
3541
'detail': message,
@@ -38,6 +44,15 @@ def exception_handler(exc, context):
3844
},
3945
'status': encoding.force_text(response.status_code),
4046
})
47+
else:
48+
errors.append({
49+
'detail': message,
50+
'source': {
51+
'pointer': pointer,
52+
},
53+
'status': encoding.force_text(response.status_code),
54+
})
55+
4156

4257
context['view'].resource_name = 'errors'
4358
response.data = errors

rest_framework_json_api/renderers.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ def render(self, data, accepted_media_type=None, renderer_context=None):
7474
resource_instance = resource_serializer.instance[position] # Get current instance
7575
json_api_data.append(
7676
utils.build_json_resource_obj(fields, resource, resource_instance, resource_name))
77-
included = utils.extract_included(fields, resource)
77+
included = utils.extract_included(fields, resource, resource_instance)
7878
if included:
7979
json_api_included.extend(included)
8080
else:
@@ -83,7 +83,7 @@ def render(self, data, accepted_media_type=None, renderer_context=None):
8383
fields = utils.get_serializer_fields(data.serializer)
8484
resource_instance = data.serializer.instance
8585
json_api_data = utils.build_json_resource_obj(fields, data, resource_instance, resource_name)
86-
included = utils.extract_included(fields, data)
86+
included = utils.extract_included(fields, data, resource_instance)
8787
if included:
8888
json_api_included.extend(included)
8989
else:

rest_framework_json_api/utils.py

+55-37
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
from django.utils import six, encoding
88
from django.utils.translation import ugettext_lazy as _
99
from rest_framework.serializers import BaseSerializer, ListSerializer, ModelSerializer
10-
from rest_framework.relations import RelatedField, HyperlinkedRelatedField, PrimaryKeyRelatedField
10+
from rest_framework.relations import RelatedField, HyperlinkedRelatedField, PrimaryKeyRelatedField, \
11+
HyperlinkedIdentityField
1112
from rest_framework.settings import api_settings
1213
from rest_framework.exceptions import APIException
1314

1415
from django.utils.six.moves.urllib.parse import urlparse
1516

16-
1717
try:
1818
from rest_framework.compat import OrderedDict
1919
except ImportError:
@@ -153,10 +153,15 @@ def get_related_resource_type(relation):
153153
parent_model = parent_serializer.Meta.model
154154
else:
155155
parent_model = parent_serializer.parent.Meta.model
156-
parent_model_relation = getattr(
157-
parent_model,
158-
(relation.source if relation.source else parent_serializer.field_name)
159-
)
156+
157+
if relation.source:
158+
if relation.source != '*':
159+
parent_model_relation = getattr(parent_model, relation.source)
160+
else:
161+
parent_model_relation = getattr(parent_model, relation.field_name)
162+
else:
163+
parent_model_relation = getattr(parent_model, parent_serializer.field_name)
164+
160165
if hasattr(parent_model_relation, 'related'):
161166
relation_model = parent_model_relation.related.model
162167
elif hasattr(parent_model_relation, 'field'):
@@ -193,11 +198,13 @@ def extract_relationships(fields, resource, resource_instance):
193198
if not isinstance(field, (RelatedField, ManyRelatedField, BaseSerializer)):
194199
continue
195200

196-
if isinstance(field, HyperlinkedRouterField):
197-
# special case for HyperlinkedRouterField
201+
if isinstance(field, HyperlinkedIdentityField):
202+
# special case for HyperlinkedIdentityField
198203
relation_data = list()
199204
relation_type = get_related_resource_type(field)
200-
related = getattr(resource_instance, field_name).all()
205+
relation_manager = getattr(resource_instance, field_name)
206+
# Don't try to query an empty relation
207+
related = relation_manager.all() if relation_manager is not None else list()
201208
for relation in related:
202209
relation_data.append(OrderedDict([('type', relation_type), ('id', encoding.force_text(relation.pk))]))
203210

@@ -213,38 +220,39 @@ def extract_relationships(fields, resource, resource_instance):
213220

214221
if isinstance(field, (PrimaryKeyRelatedField, HyperlinkedRelatedField)):
215222
relation_type = get_related_resource_type(field)
223+
relation_id = getattr(resource_instance, field_name).pk if resource.get(field_name) else None
216224

217-
if resource.get(field_name) is not None:
218-
relation_id = getattr(resource_instance, field_name).id
219-
else:
220-
relation_id = None
221-
222-
data.update(
223-
{
224-
field_name: {
225-
'data': (OrderedDict([
226-
('type', relation_type), ('id', encoding.force_text(relation_id))
227-
]) if relation_id is not None else None)
228-
}
229-
}
225+
relation_data = {
226+
'data': (OrderedDict([
227+
('type', relation_type), ('id', encoding.force_text(relation_id))
228+
]) if relation_id is not None else None)
229+
}
230+
231+
relation_data.update(
232+
{'links': {'related': resource.get(field_name)}}
233+
if isinstance(field, HyperlinkedRelatedField) and resource.get(field_name) else {}
230234
)
235+
data.update({field_name: relation_data})
231236
continue
232237

233238
if isinstance(field, ManyRelatedField):
234239
relation_data = list()
235-
236240
relation = field.child_relation
237241
relation_type = get_related_resource_type(relation)
238-
nested_resource_queryset = getattr(resource_instance, field_name).all()
239-
if isinstance(relation, (HyperlinkedRelatedField, PrimaryKeyRelatedField)):
240-
for position in range(len(nested_resource_queryset)):
241-
nested_resource_instance = nested_resource_queryset[position]
242-
relation_data.append(
243-
OrderedDict([('type', relation_type), ('id', encoding.force_text(nested_resource_instance.pk))])
244-
)
245-
246-
data.update({field_name: {'data': relation_data}})
247-
continue
242+
for related_object in getattr(resource_instance, field_name).all():
243+
relation_data.append(OrderedDict([
244+
('type', relation_type),
245+
('id', encoding.force_text(related_object.pk))
246+
]))
247+
data.update({
248+
field_name: {
249+
'data': relation_data,
250+
'meta': {
251+
'count': len(relation_data)
252+
}
253+
}
254+
})
255+
continue
248256

249257
if isinstance(field, ListSerializer):
250258
relation_data = list()
@@ -284,7 +292,7 @@ def extract_relationships(fields, resource, resource_instance):
284292
return format_keys(data)
285293

286294

287-
def extract_included(fields, resource):
295+
def extract_included(fields, resource, resource_instance):
288296
included_data = list()
289297
for field_name, field in six.iteritems(fields):
290298
# Skip URL field
@@ -305,8 +313,15 @@ def extract_included(fields, resource):
305313
serializer_fields = get_serializer_fields(serializer)
306314
serializer_data = resource.get(field_name)
307315
if isinstance(serializer_data, list):
308-
for serializer_resource in serializer_data:
309-
included_data.append(build_json_resource_obj(serializer_fields, serializer_resource, relation_type))
316+
for position in range(len(serializer_data)):
317+
serializer_resource = serializer_data[position]
318+
resource_instance_manager = getattr(resource_instance, field_name).all()
319+
nested_resource_instance = resource_instance_manager[position]
320+
included_data.append(
321+
build_json_resource_obj(
322+
serializer_fields, serializer_resource, nested_resource_instance, relation_type
323+
)
324+
)
310325

311326
if isinstance(field, ModelSerializer):
312327

@@ -316,7 +331,10 @@ def extract_included(fields, resource):
316331
# Get the serializer fields
317332
serializer_fields = get_serializer_fields(field)
318333
serializer_data = resource.get(field_name)
334+
nested_resource_instance = getattr(resource_instance, field_name).all()
319335
if serializer_data:
320-
included_data.append(build_json_resource_obj(serializer_fields, serializer_data, relation_type))
336+
included_data.append(
337+
build_json_resource_obj(serializer_fields, serializer_data, nested_resource_instance, relation_type)
338+
)
321339

322340
return format_keys(included_data)

0 commit comments

Comments
 (0)