Merge branch 'jpadilla-jsonp' into version-3.1

This commit is contained in:
Tom Christie 2014-12-03 23:15:06 +00:00
commit cd4d866021
3 changed files with 3 additions and 118 deletions

View File

@ -49,10 +49,10 @@ using the `APIView` class based views.
Or, if you're using the `@api_view` decorator with function based views.
@api_view(['GET'])
@renderer_classes((JSONRenderer, JSONPRenderer))
@renderer_classes((JSONRenderer,))
def user_count_view(request, format=None):
"""
A view that returns the count of active users, in JSON or JSONp.
A view that returns the count of active users in JSON.
"""
user_count = User.objects.filter(active=True).count()
content = {'user_count': user_count}
@ -93,26 +93,6 @@ The default JSON encoding style can be altered using the `UNICODE_JSON` and `COM
**.charset**: `None`
## JSONPRenderer
Renders the request data into `JSONP`. The `JSONP` media type provides a mechanism of allowing cross-domain AJAX requests, by wrapping a `JSON` response in a javascript callback.
The javascript callback function must be set by the client including a `callback` URL query parameter. For example `http://example.com/api/users?callback=jsonpCallback`. If the callback function is not explicitly set by the client it will default to `'callback'`.
---
**Warning**: If you require cross-domain AJAX requests, you should almost certainly be using the more modern approach of [CORS][cors] as an alternative to `JSONP`. See the [CORS documentation][cors-docs] for more details.
The `jsonp` approach is essentially a browser hack, and is [only appropriate for globally readable API endpoints][jsonp-security], where `GET` requests are unauthenticated and do not require any user permissions.
---
**.media_type**: `application/javascript`
**.format**: `'.jsonp'`
**.charset**: `utf-8`
## YAMLRenderer
Renders the request data into `YAML`.
@ -419,10 +399,6 @@ Comma-separated values are a plain-text tabular data format, that can be easily
[cite]: https://docs.djangoproject.com/en/dev/ref/template-response/#the-rendering-process
[conneg]: content-negotiation.md
[browser-accept-headers]: http://www.gethifi.com/blog/browser-rest-http-accept-headers
[rfc4627]: http://www.ietf.org/rfc/rfc4627.txt
[cors]: http://www.w3.org/TR/cors/
[cors-docs]: ../topics/ajax-csrf-cors.md
[jsonp-security]: http://stackoverflow.com/questions/613962/is-jsonp-safe-to-use
[testing]: testing.md
[HATEOAS]: http://timelessrepo.com/haters-gonna-hateoas
[quote]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven

View File

@ -103,40 +103,6 @@ class JSONRenderer(BaseRenderer):
return ret
class JSONPRenderer(JSONRenderer):
"""
Renderer which serializes to json,
wrapping the json output in a callback function.
"""
media_type = 'application/javascript'
format = 'jsonp'
callback_parameter = 'callback'
default_callback = 'callback'
charset = 'utf-8'
def get_callback(self, renderer_context):
"""
Determine the name of the callback to wrap around the json output.
"""
request = renderer_context.get('request', None)
params = request and request.query_params or {}
return params.get(self.callback_parameter, self.default_callback)
def render(self, data, accepted_media_type=None, renderer_context=None):
"""
Renders into jsonp, wrapping the json output in a callback function.
Clients may set the callback function name using a query parameter
on the URL, for example: ?callback=exampleCallbackName
"""
renderer_context = renderer_context or {}
callback = self.get_callback(renderer_context)
json = super(JSONPRenderer, self).render(data, accepted_media_type,
renderer_context)
return callback.encode(self.charset) + b'(' + json + b');'
class YAMLRenderer(BaseRenderer):
"""
Renderer which serializes to YAML.

View File

@ -12,8 +12,7 @@ from rest_framework import status, permissions
from rest_framework.compat import yaml, BytesIO
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \
JSONPRenderer, BrowsableAPIRenderer
from rest_framework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, BrowsableAPIRenderer
from rest_framework.parsers import YAMLParser
from rest_framework.settings import api_settings
from rest_framework.test import APIRequestFactory
@ -105,8 +104,6 @@ urlpatterns = patterns(
url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderer_classes=[RendererA, RendererB])),
url(r'^$', MockView.as_view(renderer_classes=[RendererA, RendererB])),
url(r'^cache$', MockGETView.as_view()),
url(r'^jsonp/jsonrenderer$', MockGETView.as_view(renderer_classes=[JSONRenderer, JSONPRenderer])),
url(r'^jsonp/nojsonrenderer$', MockGETView.as_view(renderer_classes=[JSONPRenderer])),
url(r'^parseerror$', MockPOSTView.as_view(renderer_classes=[JSONRenderer, BrowsableAPIRenderer])),
url(r'^html$', HTMLView.as_view()),
url(r'^html1$', HTMLView1.as_view()),
@ -397,60 +394,6 @@ class AsciiJSONRendererTests(TestCase):
self.assertEqual(content, '{"countries":["United Kingdom","France","Espa\\u00f1a"]}'.encode('utf-8'))
class JSONPRendererTests(TestCase):
"""
Tests specific to the JSONP Renderer
"""
urls = 'tests.test_renderers'
def test_without_callback_with_json_renderer(self):
"""
Test JSONP rendering with View JSON Renderer.
"""
resp = self.client.get(
'/jsonp/jsonrenderer',
HTTP_ACCEPT='application/javascript'
)
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual(resp['Content-Type'], 'application/javascript; charset=utf-8')
self.assertEqual(
resp.content,
('callback(%s);' % _flat_repr).encode('ascii')
)
def test_without_callback_without_json_renderer(self):
"""
Test JSONP rendering without View JSON Renderer.
"""
resp = self.client.get(
'/jsonp/nojsonrenderer',
HTTP_ACCEPT='application/javascript'
)
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual(resp['Content-Type'], 'application/javascript; charset=utf-8')
self.assertEqual(
resp.content,
('callback(%s);' % _flat_repr).encode('ascii')
)
def test_with_callback(self):
"""
Test JSONP rendering with callback function name.
"""
callback_func = 'myjsonpcallback'
resp = self.client.get(
'/jsonp/nojsonrenderer?callback=' + callback_func,
HTTP_ACCEPT='application/javascript'
)
self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual(resp['Content-Type'], 'application/javascript; charset=utf-8')
self.assertEqual(
resp.content,
('%s(%s);' % (callback_func, _flat_repr)).encode('ascii')
)
if yaml:
_yaml_repr = 'foo: [bar, baz]\n'