Skip to content

Sideload resources #8

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Sep 8, 2014
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 24 additions & 5 deletions README.rst
Original file line number Diff line number Diff line change
@@ -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
^^^^^^^^^^^^^^^^^^^^^^

@@ -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
@@ -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.
@@ -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
@@ -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
@@ -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')
4 changes: 2 additions & 2 deletions rest_framework_ember/utils.py
Original file line number Diff line number Diff line change
@@ -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')