Skip to content

Commit dc93608

Browse files
committedSep 8, 2014
Merge pull request #8 from ngenworks/sideload-resources
Allow developers to opt out of having the root JSON key automatically added
2 parents 4a3e989 + 5e38c15 commit dc93608

File tree

6 files changed

+101
-10
lines changed

6 files changed

+101
-10
lines changed
 

‎README.rst

+24-5
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,12 @@ override ``settings.REST_FRAMEWORK``::
117117
}
118118

119119

120+
120121
If ``PAGINATE_BY`` is set the renderer will return a ``meta`` object with
121122
record count and the next and previous links. Django Rest Framework looks
122123
for the ``page`` GET parameter by default allowing you to make requests for
123124
subsets of the data with ``this.store.find('identity', {page: 2});``.
124125

125-
126126
resource_name property
127127
^^^^^^^^^^^^^^^^^^^^^^
128128

@@ -216,16 +216,35 @@ To display a specific error inline use the following::
216216
{{/each}}
217217
{{input name="title" value=title}}
218218

219-
======
219+
220+
---------------------
221+
Sideloading Resources
222+
---------------------
223+
224+
If you are using the JSON Renderer globally, this can lead to issues
225+
when hitting endpoints that are intended to sideload other objects.
226+
227+
For example::
228+
229+
{
230+
"users": [],
231+
"cars": []
232+
}
233+
234+
235+
Set the ``resource_name`` property on the object to ``False``, and the data
236+
will be returned as it is above.
237+
238+
239+
------
220240
Mixins
221-
======
241+
------
222242

223243
The following mixin classes are available to use with Rest Framework
224244
resources.
225245

226-
-------------------------------------------
227246
rest_framework_ember.mixins.MultipleIDMixin
228-
-------------------------------------------
247+
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
229248

230249
Overrides ``get_queryset`` to filter by ``ids[]`` in URL query params.
231250

‎example/api/api.py

+37
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,21 @@ class Meta:
1919
'id', 'first_name', 'last_name', 'email', )
2020

2121

22+
class CarSerializer(serializers.Serializer):
23+
"""
24+
Cars serializer
25+
"""
26+
name = serializers.CharField(max_length=50)
27+
28+
29+
class UserCarSerializer(serializers.Serializer):
30+
"""
31+
Serializer that returns a list of users & cars.
32+
"""
33+
users = IdentitySerializer(many=True)
34+
cars = CarSerializer(many=True)
35+
36+
2237
class User(generics.GenericAPIView):
2338
"""
2439
Current user's identity endpoint.
@@ -63,3 +78,25 @@ class MultipleIDMixinUserModelViewSet(mixins.MultipleIDMixin,
6378

6479
queryset = auth_models.User.objects.all()
6580

81+
82+
class UserCarResource(UserEmber):
83+
"""
84+
Resource that returns a list of users and cars.
85+
"""
86+
resource_name = False
87+
88+
cars = [
89+
{'id': 1, 'name': 'BMW'},
90+
{'id': 2, 'name': 'Mercedes'},
91+
{'id': 3, 'name': 'Mini'},
92+
{'id': 4, 'name': 'Ford'}
93+
]
94+
95+
def get(self, request, *args, **kwargs):
96+
data = {
97+
'users': self.get_queryset(),
98+
'cars': self.cars
99+
}
100+
serializer = UserCarSerializer(data)
101+
return Response(serializer.data)
102+

‎example/api/urls.py

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,25 @@
22
Example app URLs
33
"""
44
from django.conf.urls import patterns, include, url
5-
from .api import User, UserEmber, EmberUserModelViewSet, MultipleIDMixinUserModelViewSet
5+
from .api import (
6+
User, UserEmber, EmberUserModelViewSet, MultipleIDMixinUserModelViewSet,
7+
UserCarResource)
68

79
from rest_framework import routers
810

911
urlpatterns = patterns('',
1012
url(r'^user-default/(?P<pk>\d+)/$', User.as_view(), name='user-default'),
1113
url(r'^user-ember/(?P<pk>\d+)/$', UserEmber.as_view(), name='user-ember'),
12-
url(r'^user-mixin-viewset/$', MultipleIDMixinUserModelViewSet.as_view({'get': 'list'}),
14+
url(r'^user-mixin-viewset/$',
15+
MultipleIDMixinUserModelViewSet.as_view({'get': 'list'}),
1316
name='mixin-user-list'),
1417
url(r'^user-viewset/$', EmberUserModelViewSet.as_view({'get': 'list'}),
1518
name='user-list'),
1619
url(r'^user-viewset/(?P<pk>\d+)/$',
1720
EmberUserModelViewSet.as_view(
18-
{'get': 'retrieve', 'post': 'create', 'put': 'update'}), name='user-detail'),
21+
{'get': 'retrieve', 'post': 'create', 'put': 'update'}),
22+
name='user-detail'),
23+
url(r'users-cars/$', UserCarResource.as_view(),
24+
name='users-cars'),
1925
)
2026

+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
"""
2+
Test sideloading resources
3+
"""
4+
import json
5+
from example.tests import TestBase
6+
from django.core.urlresolvers import reverse_lazy
7+
from django.conf import settings
8+
9+
10+
class SideloadResourceTest(TestBase):
11+
"""
12+
Test that sideloading resources returns expected output.
13+
"""
14+
url = reverse_lazy('users-cars')
15+
16+
def test_get_sideloaded_data(self):
17+
"""
18+
Ensure resources that are meant for sideloaded data
19+
do not return a single root key.
20+
"""
21+
response = self.client.get(self.url)
22+
content = json.loads(response.content)
23+
24+
self.assertEqual(content.keys(), ['cars', 'users'])
25+

‎rest_framework_ember/renderers.py

+4
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ def render(self, data, accepted_media_type=None, renderer_context=None):
2121

2222
resource_name = get_resource_name(view)
2323

24+
if resource_name == False:
25+
return super(JSONRenderer, self).render(
26+
data, accepted_media_type, renderer_context)
27+
2428
try:
2529
data_copy = copy.copy(data)
2630
content = data_copy.pop('results')

‎rest_framework_ember/utils.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
def get_resource_name(view):
66
"""
7-
Return the name of a resource
8-
"""
7+
Return the name of a resource
8+
"""
99
try:
1010
# is the resource name set directly on the view?
1111
resource_name = getattr(view, 'resource_name')

0 commit comments

Comments
 (0)
Please sign in to comment.