Skip to content
Closed
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0ff04d2
Added inflection for camel/pluralization of attributes and resource name
Sep 16, 2014
557208f
Added inflection to packages
Sep 16, 2014
44807ec
Added inflection to packages
Sep 16, 2014
c0f5839
Removed unused cruft.
Sep 16, 2014
6dbfdfc
Merge pull request #1 from epicowl/master
derekbedwards Sep 16, 2014
a2ff594
Added underscoreize to parser, fixed pluralization.
Sep 16, 2014
6151849
Merge pull request #2 from epicowl/master
derekbedwards Sep 16, 2014
498ea5c
Fixed bad output, doh
Sep 16, 2014
cfeb24b
Merge pull request #3 from epicowl/master
derekbedwards Sep 16, 2014
cf451bc
Added inflection for proper camelization/underscore/pluralization
Sep 27, 2014
aa05b05
Prep for pull request
Sep 27, 2014
336e80b
Added inflection for pluralization, camelization and underscores of r…
Sep 16, 2014
b66bf98
Merge branch 'develop' of https://github.com/epicowl/rest_framework_e…
Sep 27, 2014
9ec176a
Changed renderer name
Sep 27, 2014
867eab1
Fixed get_resource_name and reverted comments
Oct 1, 2014
63699f5
Updated renderer and tests to cover inflection
Oct 8, 2014
a03e56c
Fixes for updates to tests
Oct 8, 2014
e42f087
Merge branch 'develop' of https://github.com/epicowl/rest_framework_e…
Oct 8, 2014
2a8cf98
Start trying to make backwards compat for camelization
gaker Oct 30, 2014
9c0287d
Add REST_FRAMEWORK_PLURALIZE_KEYS setting.
gaker Oct 30, 2014
faef942
Fixed problem with structure of renderer
Oct 30, 2014
dba87f4
Fixed structure issue
Oct 31, 2014
f2070ce
Updated camelization renderer, abstracted camelize_keys to utils
Nov 11, 2014
0593984
Made format_keys function that handles both camelize and underscore
Nov 11, 2014
7b51eb3
Merged develop brange, adds support for format_keys to handle cameliz…
Nov 11, 2014
690a4a1
Adds format_keys function which optionally camelizes or underscores t…
Sep 16, 2014
c0cef73
Updated getattr of settings configs
Nov 11, 2014
eb0318d
Fixed typo
Nov 11, 2014
23f384c
Reverted tests to original state
Nov 15, 2014
0894170
Added format resource name function, added simple unit tests for came…
Nov 15, 2014
d9b6a79
Last fix
Nov 15, 2014
fb22f4a
Update README.rst
Nov 16, 2014
fcebeb6
Merged with develop.
Nov 16, 2014
b19be45
Update README.rst
Nov 16, 2014
fd74b70
Merge branch 'develop' of https://github.com/erichonkanen/rest_framew…
Nov 16, 2014
eb2a081
Merge branch 'master' of https://github.com/coachlogix/rest_framework…
Nov 19, 2014
8cc86bd
Fixed typo in readme
Nov 19, 2014
33aab31
Updated parser to use format_keys
Nov 19, 2014
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
115 changes: 60 additions & 55 deletions example/tests/test_model_viewsets.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@


import json

from example.tests import TestBase
from django.contrib.auth import get_user_model
from django.core.urlresolvers import reverse, reverse_lazy
Expand All @@ -9,9 +8,11 @@

class ModelViewSetTests(TestBase):
"""
Test usage with ModelViewSets
Test usage with ModelViewSets, also tests pluralization, camelization,
and underscore.

[<RegexURLPattern user-list ^user-viewsets/$>, <RegexURLPattern user-detail ^user-viewsets/(?P<pk>[^/]+)/$>]
[<RegexURLPattern user-list ^user-viewsets/$>,
<RegexURLPattern user-detail ^user-viewsets/(?P<pk>[^/]+)/$>]
"""
list_url = reverse_lazy('user-list')

Expand All @@ -21,29 +22,31 @@ def setUp(self):

def test_key_in_list_result(self):
"""
Ensure the result has a "user" key since that is the name of the model
Ensure the result has a 'user' key since that is the name of the model
"""
response = self.client.get(self.list_url)
self.assertEqual(response.status_code, 200)

user = get_user_model().objects.all()[0]
expected = {"user": [{
'id': user.pk,
'first_name': user.first_name,
'last_name': user.last_name,
'email': user.email
}]}
expected = {
u'user': [{
u'id': user.pk,
u'firstName': user.first_name,
u'lastName': user.last_name,
u'email': user.email
}]
}

json_content = json.loads(response.content)
meta = json_content.get("meta")
meta = json_content.get('meta')

self.assertEquals(expected.get('user'), json_content.get('user'))
self.assertEquals(meta.get('count', 0),
get_user_model().objects.count())
self.assertEquals(meta.get("next"), 2)
self.assertEquals(meta.get('next'), 2)
self.assertEqual('http://testserver/user-viewset/?page=2',
meta.get("next_link"))
self.assertEqual(meta.get("page"), 1)
meta.get('nextLink'))
self.assertEqual(meta.get('page'), 1)

def test_page_two_in_list_result(self):
"""
Expand All @@ -53,72 +56,75 @@ def test_page_two_in_list_result(self):
self.assertEqual(response.status_code, 200)

user = get_user_model().objects.all()[1]
expected = {"user": [{
'id': user.pk,
'first_name': user.first_name,
'last_name': user.last_name,
'email': user.email
}]}
expected = {
u'user': [{
u'id': user.pk,
u'firstName': user.first_name,
u'lastName': user.last_name,
u'email': user.email
}]
}

json_content = json.loads(response.content)
meta = json_content.get("meta")
meta = json_content.get('meta')

self.assertEquals(expected.get('user'), json_content.get('user'))
self.assertEquals(meta.get('count', 0),
get_user_model().objects.count())
self.assertIsNone(meta.get("next"))
self.assertIsNone(meta.get("next_link"))
self.assertEqual(meta.get("previous"), 1)
self.assertIsNone(meta.get('next'))
self.assertIsNone(meta.get('next_link'))
self.assertEqual(meta.get('previous'), 1)
self.assertEqual('http://testserver/user-viewset/?page=1',
meta.get("previous_link"))
self.assertEqual(meta.get("page"), 2)
meta.get('previousLink'))
self.assertEqual(meta.get('page'), 2)

def test_page_range_in_list_result(self):
"""
Ensure that the range of a page can be changed from the client.
Ensure that the range of a page can be changed from the client,
tests pluralization as two objects means it converts ``user`` to
``users``.
"""
response = self.client.get(self.list_url, {'page_size': 2})
self.assertEqual(response.status_code, 200)

users = get_user_model().objects.all()
expected = {"user": [
{
'id': users[0].pk,
'first_name': users[0].first_name,
'last_name': users[0].last_name,
'email': users[0].email
},
{
'id': users[1].pk,
'first_name': users[1].first_name,
'last_name': users[1].last_name,
'email': users[1].email
}]}
expected = {
u'users': [{
u'id': users[0].pk,
u'firstName': users[0].first_name,
u'lastName': users[0].last_name,
u'email': users[0].email
},{
u'id': users[1].pk,
u'firstName': users[1].first_name,
u'lastName': users[1].last_name,
u'email': users[1].email
}]
}

json_content = json.loads(response.content)
meta = json_content.get("meta")
meta = json_content.get('meta')
self.assertEquals(expected.get('user'), json_content.get('user'))
self.assertEquals(meta.get('count', 0),
get_user_model().objects.count())


def test_key_in_detail_result(self):
"""
Ensure the result has a "user" key.
Ensure the result has a 'user' key.
"""
response = self.client.get(self.detail_url)
self.assertEqual(response.status_code, 200)

result = json.loads(response.content)
expected = {
'user': {
'id': self.miles.pk,
'first_name': self.miles.first_name,
'last_name': self.miles.last_name,
'email': self.miles.email
u'user': {
u'id': self.miles.pk,
u'firstName': self.miles.first_name,
u'lastName': self.miles.last_name,
u'email': self.miles.email
}
}

self.assertEqual(result, expected)

def test_key_in_post(self):
Expand All @@ -127,11 +133,11 @@ def test_key_in_post(self):
"""
self.client.login(username='miles', password='pw')
data = {
'user': {
'id': self.miles.pk,
'first_name': self.miles.first_name,
'last_name': self.miles.last_name,
'email': 'miles@trumpet.org'
u'user': {
u'id': self.miles.pk,
u'firstName': self.miles.first_name,
u'lastName': self.miles.last_name,
u'email': 'miles@trumpet.org'
}
}
response = self.client.put(self.detail_url, data=data, format='json')
Expand All @@ -145,4 +151,3 @@ def test_key_in_post(self):
self.assertEqual(
get_user_model().objects.get(pk=self.miles.pk).email,
'miles@trumpet.org')

38 changes: 18 additions & 20 deletions example/tests/test_multiple_id_mixin.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@


import json
from example.tests import TestBase
from django.contrib.auth import get_user_model
Expand All @@ -25,22 +23,22 @@ def test_single_id_in_query_params(self):
self.assertEqual(response.status_code, 200)

expected = {
'user': [{
'id': self.miles.pk,
'first_name': self.miles.first_name,
'last_name': self.miles.last_name,
'email': self.miles.email
u'user': [{
u'id': self.miles.pk,
u'firstName': self.miles.first_name,
u'lastName': self.miles.last_name,
u'email': self.miles.email
}]
}

json_content = json.loads(response.content)
meta = json_content.get("meta")
meta = json_content.get('meta')

self.assertEquals(expected.get('user'), json_content.get('user'))
self.assertEquals(meta.get('count', 0), 1)
self.assertEquals(meta.get("next"), None)
self.assertEqual(None, meta.get("next_link"))
self.assertEqual(meta.get("page"), 1)
self.assertEquals(meta.get('next'), None)
self.assertEqual(None, meta.get('nextLink'))
self.assertEqual(meta.get('page'), 1)

def test_multiple_ids_in_query_params(self):
"""
Expand All @@ -52,22 +50,22 @@ def test_multiple_ids_in_query_params(self):
self.assertEqual(response.status_code, 200)

expected = {
'user': [{
'id': self.john.pk,
'first_name': self.john.first_name,
'last_name': self.john.last_name,
'email': self.john.email
u'user': [{
u'id': self.john.pk,
u'firstName': self.john.first_name,
u'lastName': self.john.last_name,
u'email': self.john.email
}]
}

json_content = json.loads(response.content)
meta = json_content.get("meta")
meta = json_content.get('meta')

self.assertEquals(expected.get('user'), json_content.get('user'))
self.assertEquals(meta.get('count', 0), 2)
self.assertEquals(meta.get("next"), 2)
self.assertEquals(meta.get('next'), 2)
self.assertEqual(
'http://testserver/user-mixin-viewset/?ids%5B%5D=2&ids%5B%5D=1&page=2',
meta.get("next_link"))
self.assertEqual(meta.get("page"), 1)
meta.get('nextLink'))
self.assertEqual(meta.get('page'), 1)

15 changes: 9 additions & 6 deletions rest_framework_ember/parsers.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
"""
Parsers
"""
import inflection

from rest_framework.parsers import JSONParser
Expand All @@ -23,9 +26,9 @@ def parse(self, stream, media_type=None, parser_context=None):
"""
Parses the incoming bytestream as JSON and returns the resulting data
"""
data = super(EmberJSONParser, self).parse(stream, media_type=None,
parser_context=None)
data = data.get(get_resource_name(parser_context.get('view', None)))
for item in data:
data[inflection.underscore(item)] = data.pop(item)
return data
result = super(EmberJSONParser, self).parse(stream, media_type=None,
parser_context=None)
resource = result.get(get_resource_name(parser_context.get('view', None)))
for item in resource:
resource[inflection.underscore(item)] = resource.pop(item)
return resource
44 changes: 29 additions & 15 deletions rest_framework_ember/renderers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,55 @@
from rest_framework_ember.utils import get_resource_name


class EmberJSONRenderer(renderers.JSONRenderer):
class JSONRenderer(renderers.JSONRenderer):
"""
Render a JSON response the way Ember Data wants it. Such as:
{
"resource": {
"company": {
"id": 1,
"field": "lorem ipsum",
"pub_date": "2014-03-13 16:33:37"
"name": "nGen Works",
"slug": "ngen-works",
"date_created": "2014-03-13 16:33:37"
}
}
"""
def render(self, data, accepted_media_type=None, renderer_context=None):
view = renderer_context.get('view')
resource_name = get_resource_name(view)

if isinstance(data, dict):
for key, value in data.items():
data[inflection.camelize(key, False)] = data.pop(key)

elif isinstance(data, (list, tuple)):
for obj in data:
if hasattr(obj, 'items'):
for key, value in obj.items():
obj[inflection.camelize(key, False)] = obj.pop(key)
resource_name = inflection.pluralize(resource_name)

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')

# Handle meta
for key, value in data_copy.items():
data_copy[inflection.camelize(key, False)] = data_copy.pop(key)

if isinstance(content, dict):
for key, value in content.items():
content[inflection.camelize(key, False)] = content.pop(key)

elif isinstance(content, (list, tuple)):
for obj in content:
if hasattr(obj, 'items'):
for key, value in obj.items():
obj[inflection.camelize(key, False)] = obj.pop(key)

if len(content) > 1:
resource_name = inflection.pluralize(resource_name)

data = {resource_name : content, "meta" : data_copy}
except (TypeError, KeyError, AttributeError) as e:

# Default behavior
if not resource_name == 'data':
for key, value in data.items():
data[inflection.camelize(key, False)] = data.pop(key)

data = {resource_name : data}
return super(JSONRenderer, self).render(
data, accepted_media_type, renderer_context)
2 changes: 1 addition & 1 deletion rest_framework_ember/utils.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import inflection


def get_resource(view):
def get_resource_name(view):
"""Return the name of a resource."""
try:
# Check the view
Expand Down