Skip to content

Commit

Permalink
Merge pull request #8 from ngenworks/sideload-resources
Browse files Browse the repository at this point in the history
Allow developers to opt out of having the root JSON key automatically added
  • Loading branch information
jerel committed Sep 8, 2014
2 parents 4a3e989 + 5e38c15 commit dc93608
Show file tree
Hide file tree
Showing 6 changed files with 101 additions and 10 deletions.
29 changes: 24 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,12 @@ override ``settings.REST_FRAMEWORK``::
}



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


resource_name property
^^^^^^^^^^^^^^^^^^^^^^

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

======

---------------------
Sideloading Resources
---------------------

If you are using the JSON Renderer globally, this can lead to issues
when hitting endpoints that are intended to sideload other objects.

For example::

{
"users": [],
"cars": []
}


Set the ``resource_name`` property on the object to ``False``, and the data
will be returned as it is above.


------
Mixins
======
------

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

-------------------------------------------
rest_framework_ember.mixins.MultipleIDMixin
-------------------------------------------
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

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

37 changes: 37 additions & 0 deletions example/api/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ class Meta:
'id', 'first_name', 'last_name', 'email', )


class CarSerializer(serializers.Serializer):
"""
Cars serializer
"""
name = serializers.CharField(max_length=50)


class UserCarSerializer(serializers.Serializer):
"""
Serializer that returns a list of users & cars.
"""
users = IdentitySerializer(many=True)
cars = CarSerializer(many=True)


class User(generics.GenericAPIView):
"""
Current user's identity endpoint.
Expand Down Expand Up @@ -63,3 +78,25 @@ class MultipleIDMixinUserModelViewSet(mixins.MultipleIDMixin,

queryset = auth_models.User.objects.all()


class UserCarResource(UserEmber):
"""
Resource that returns a list of users and cars.
"""
resource_name = False

cars = [
{'id': 1, 'name': 'BMW'},
{'id': 2, 'name': 'Mercedes'},
{'id': 3, 'name': 'Mini'},
{'id': 4, 'name': 'Ford'}
]

def get(self, request, *args, **kwargs):
data = {
'users': self.get_queryset(),
'cars': self.cars
}
serializer = UserCarSerializer(data)
return Response(serializer.data)

12 changes: 9 additions & 3 deletions example/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,19 +2,25 @@
Example app URLs
"""
from django.conf.urls import patterns, include, url
from .api import User, UserEmber, EmberUserModelViewSet, MultipleIDMixinUserModelViewSet
from .api import (
User, UserEmber, EmberUserModelViewSet, MultipleIDMixinUserModelViewSet,
UserCarResource)

from rest_framework import routers

urlpatterns = patterns('',
url(r'^user-default/(?P<pk>\d+)/$', User.as_view(), name='user-default'),
url(r'^user-ember/(?P<pk>\d+)/$', UserEmber.as_view(), name='user-ember'),
url(r'^user-mixin-viewset/$', MultipleIDMixinUserModelViewSet.as_view({'get': 'list'}),
url(r'^user-mixin-viewset/$',
MultipleIDMixinUserModelViewSet.as_view({'get': 'list'}),
name='mixin-user-list'),
url(r'^user-viewset/$', EmberUserModelViewSet.as_view({'get': 'list'}),
name='user-list'),
url(r'^user-viewset/(?P<pk>\d+)/$',
EmberUserModelViewSet.as_view(
{'get': 'retrieve', 'post': 'create', 'put': 'update'}), name='user-detail'),
{'get': 'retrieve', 'post': 'create', 'put': 'update'}),
name='user-detail'),
url(r'users-cars/$', UserCarResource.as_view(),
name='users-cars'),
)

25 changes: 25 additions & 0 deletions example/tests/test_sideload_resources.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"""
Test sideloading resources
"""
import json
from example.tests import TestBase
from django.core.urlresolvers import reverse_lazy
from django.conf import settings


class SideloadResourceTest(TestBase):
"""
Test that sideloading resources returns expected output.
"""
url = reverse_lazy('users-cars')

def test_get_sideloaded_data(self):
"""
Ensure resources that are meant for sideloaded data
do not return a single root key.
"""
response = self.client.get(self.url)
content = json.loads(response.content)

self.assertEqual(content.keys(), ['cars', 'users'])

4 changes: 4 additions & 0 deletions rest_framework_ember/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def render(self, data, accepted_media_type=None, renderer_context=None):

resource_name = get_resource_name(view)

if resource_name == False:
return super(JSONRenderer, self).render(
data, accepted_media_type, renderer_context)

try:
data_copy = copy.copy(data)
content = data_copy.pop('results')
Expand Down
4 changes: 2 additions & 2 deletions rest_framework_ember/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

def get_resource_name(view):
"""
Return the name of a resource
"""
Return the name of a resource
"""
try:
# is the resource name set directly on the view?
resource_name = getattr(view, 'resource_name')
Expand Down

0 comments on commit dc93608

Please sign in to comment.