Commit 1b28339e by Marko Tibold

Merge remote-tracking branch 'upstream/master'

parents 91cee26a a0c4dca9
...@@ -20,6 +20,7 @@ Andrew McCloud <amccloud> ...@@ -20,6 +20,7 @@ Andrew McCloud <amccloud>
Thomas Steinacher <thomasst> Thomas Steinacher <thomasst>
Meurig Freeman <meurig> Meurig Freeman <meurig>
Anthony Nemitz <anemitz> Anthony Nemitz <anemitz>
Ewoud Kohl van Wijngaarden <ekohl>
THANKS TO: THANKS TO:
......
0.3.0
* JSONP Support
* Bugfixes, including support for latest markdown release
0.2.4 0.2.4
* Fix broken IsAdminUser permission. * Fix broken IsAdminUser permission.
......
__version__ = '0.2.4' __version__ = '0.3.1-dev'
VERSION = __version__ # synonym VERSION = __version__ # synonym
...@@ -26,6 +26,7 @@ __all__ = ( ...@@ -26,6 +26,7 @@ __all__ = (
'BaseRenderer', 'BaseRenderer',
'TemplateRenderer', 'TemplateRenderer',
'JSONRenderer', 'JSONRenderer',
'JSONPRenderer',
'DocumentingHTMLRenderer', 'DocumentingHTMLRenderer',
'DocumentingXHTMLRenderer', 'DocumentingXHTMLRenderer',
'DocumentingPlainTextRenderer', 'DocumentingPlainTextRenderer',
...@@ -113,6 +114,28 @@ class JSONRenderer(BaseRenderer): ...@@ -113,6 +114,28 @@ class JSONRenderer(BaseRenderer):
return json.dumps(obj, cls=DateTimeAwareJSONEncoder, indent=indent, sort_keys=sort_keys) return json.dumps(obj, cls=DateTimeAwareJSONEncoder, indent=indent, sort_keys=sort_keys)
class JSONPRenderer(JSONRenderer):
"""
Renderer which serializes to JSONP
"""
media_type = 'application/json-p'
format = 'json-p'
renderer_class = JSONRenderer
callback_parameter = 'callback'
def _get_callback(self):
return self.view.request.GET.get(self.callback_parameter, self.callback_parameter)
def _get_renderer(self):
return self.renderer_class(self.view)
def render(self, obj=None, media_type=None):
callback = self._get_callback()
json = self._get_renderer().render(obj, media_type)
return "%s(%s);" % (callback, json)
class XMLRenderer(BaseRenderer): class XMLRenderer(BaseRenderer):
""" """
Renderer which serializes to XML. Renderer which serializes to XML.
...@@ -376,6 +399,7 @@ class DocumentingPlainTextRenderer(DocumentingTemplateRenderer): ...@@ -376,6 +399,7 @@ class DocumentingPlainTextRenderer(DocumentingTemplateRenderer):
DEFAULT_RENDERERS = ( JSONRenderer, DEFAULT_RENDERERS = ( JSONRenderer,
JSONPRenderer,
DocumentingHTMLRenderer, DocumentingHTMLRenderer,
DocumentingXHTMLRenderer, DocumentingXHTMLRenderer,
DocumentingPlainTextRenderer, DocumentingPlainTextRenderer,
......
from django.conf.urls.defaults import patterns, url from django.conf.urls.defaults import patterns, url
from django import http
from django.test import TestCase from django.test import TestCase
from djangorestframework import status from djangorestframework import status
from djangorestframework.views import View
from djangorestframework.compat import View as DjangoView from djangorestframework.compat import View as DjangoView
from djangorestframework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer,\ from djangorestframework.renderers import BaseRenderer, JSONRenderer, YAMLRenderer, \
XMLRenderer XMLRenderer, JSONPRenderer
from djangorestframework.parsers import JSONParser, YAMLParser from djangorestframework.parsers import JSONParser, YAMLParser
from djangorestframework.mixins import ResponseMixin from djangorestframework.mixins import ResponseMixin
from djangorestframework.response import Response from djangorestframework.response import Response
from djangorestframework.utils.mediatypes import add_media_type_param
from StringIO import StringIO from StringIO import StringIO
import datetime import datetime
...@@ -21,20 +20,23 @@ DUMMYCONTENT = 'dummycontent' ...@@ -21,20 +20,23 @@ DUMMYCONTENT = 'dummycontent'
RENDERER_A_SERIALIZER = lambda x: 'Renderer A: %s' % x RENDERER_A_SERIALIZER = lambda x: 'Renderer A: %s' % x
RENDERER_B_SERIALIZER = lambda x: 'Renderer B: %s' % x RENDERER_B_SERIALIZER = lambda x: 'Renderer B: %s' % x
class RendererA(BaseRenderer): class RendererA(BaseRenderer):
media_type = 'mock/renderera' media_type = 'mock/renderera'
format="formata" format = "formata"
def render(self, obj=None, media_type=None): def render(self, obj=None, media_type=None):
return RENDERER_A_SERIALIZER(obj) return RENDERER_A_SERIALIZER(obj)
class RendererB(BaseRenderer): class RendererB(BaseRenderer):
media_type = 'mock/rendererb' media_type = 'mock/rendererb'
format="formatb" format = "formatb"
def render(self, obj=None, media_type=None): def render(self, obj=None, media_type=None):
return RENDERER_B_SERIALIZER(obj) return RENDERER_B_SERIALIZER(obj)
class MockView(ResponseMixin, DjangoView): class MockView(ResponseMixin, DjangoView):
renderers = (RendererA, RendererB) renderers = (RendererA, RendererB)
...@@ -43,9 +45,16 @@ class MockView(ResponseMixin, DjangoView): ...@@ -43,9 +45,16 @@ class MockView(ResponseMixin, DjangoView):
return self.render(response) return self.render(response)
class MockGETView(View):
def get(self, request, **kwargs):
return {'foo': ['bar', 'baz']}
urlpatterns = patterns('', urlpatterns = patterns('',
url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderers=[RendererA, RendererB])), url(r'^.*\.(?P<format>.+)$', MockView.as_view(renderers=[RendererA, RendererB])),
url(r'^$', MockView.as_view(renderers=[RendererA, RendererB])), url(r'^$', MockView.as_view(renderers=[RendererA, RendererB])),
url(r'^jsonp/jsonrenderer$', MockGETView.as_view(renderers=[JSONRenderer, JSONPRenderer])),
url(r'^jsonp/nojsonrenderer$', MockGETView.as_view(renderers=[JSONPRenderer])),
) )
...@@ -147,13 +156,7 @@ class RendererIntegrationTests(TestCase): ...@@ -147,13 +156,7 @@ class RendererIntegrationTests(TestCase):
self.assertEquals(resp.status_code, DUMMYSTATUS) self.assertEquals(resp.status_code, DUMMYSTATUS)
_flat_repr = '{"foo": ["bar", "baz"]}' _flat_repr = '{"foo": ["bar", "baz"]}'
_indented_repr = '{\n "foo": [\n "bar", \n "baz"\n ]\n}'
_indented_repr = """{
"foo": [
"bar",
"baz"
]
}"""
class JSONRendererTests(TestCase): class JSONRendererTests(TestCase):
...@@ -165,7 +168,7 @@ class JSONRendererTests(TestCase): ...@@ -165,7 +168,7 @@ class JSONRendererTests(TestCase):
""" """
Test basic JSON rendering. Test basic JSON rendering.
""" """
obj = {'foo':['bar','baz']} obj = {'foo': ['bar', 'baz']}
renderer = JSONRenderer(None) renderer = JSONRenderer(None)
content = renderer.render(obj, 'application/json') content = renderer.render(obj, 'application/json')
self.assertEquals(content, _flat_repr) self.assertEquals(content, _flat_repr)
...@@ -174,7 +177,7 @@ class JSONRendererTests(TestCase): ...@@ -174,7 +177,7 @@ class JSONRendererTests(TestCase):
""" """
Test JSON rendering with additional content type arguments supplied. Test JSON rendering with additional content type arguments supplied.
""" """
obj = {'foo':['bar','baz']} obj = {'foo': ['bar', 'baz']}
renderer = JSONRenderer(None) renderer = JSONRenderer(None)
content = renderer.render(obj, 'application/json; indent=2') content = renderer.render(obj, 'application/json; indent=2')
self.assertEquals(content, _indented_repr) self.assertEquals(content, _indented_repr)
...@@ -184,7 +187,7 @@ class JSONRendererTests(TestCase): ...@@ -184,7 +187,7 @@ class JSONRendererTests(TestCase):
Test rendering and then parsing returns the original object. Test rendering and then parsing returns the original object.
IE obj -> render -> parse -> obj. IE obj -> render -> parse -> obj.
""" """
obj = {'foo':['bar','baz']} obj = {'foo': ['bar', 'baz']}
renderer = JSONRenderer(None) renderer = JSONRenderer(None)
parser = JSONParser(None) parser = JSONParser(None)
...@@ -194,11 +197,48 @@ class JSONRendererTests(TestCase): ...@@ -194,11 +197,48 @@ class JSONRendererTests(TestCase):
self.assertEquals(obj, data) self.assertEquals(obj, data)
class JSONPRendererTests(TestCase):
"""
Tests specific to the JSONP Renderer
"""
urls = 'djangorestframework.tests.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/json-p')
self.assertEquals(resp.status_code, 200)
self.assertEquals(resp['Content-Type'], 'application/json-p')
self.assertEquals(resp.content, 'callback(%s);' % _flat_repr)
def test_without_callback_without_json_renderer(self):
"""
Test JSONP rendering without View JSON Renderer.
"""
resp = self.client.get('/jsonp/nojsonrenderer',
HTTP_ACCEPT='application/json-p')
self.assertEquals(resp.status_code, 200)
self.assertEquals(resp['Content-Type'], 'application/json-p')
self.assertEquals(resp.content, 'callback(%s);' % _flat_repr)
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/json-p')
self.assertEquals(resp.status_code, 200)
self.assertEquals(resp['Content-Type'], 'application/json-p')
self.assertEquals(resp.content, '%s(%s);' % (callback_func, _flat_repr))
if YAMLRenderer: if YAMLRenderer:
_yaml_repr = 'foo: [bar, baz]\n' _yaml_repr = 'foo: [bar, baz]\n'
class YAMLRendererTests(TestCase): class YAMLRendererTests(TestCase):
""" """
Tests specific to the JSON Renderer Tests specific to the JSON Renderer
...@@ -208,18 +248,17 @@ if YAMLRenderer: ...@@ -208,18 +248,17 @@ if YAMLRenderer:
""" """
Test basic YAML rendering. Test basic YAML rendering.
""" """
obj = {'foo':['bar','baz']} obj = {'foo': ['bar', 'baz']}
renderer = YAMLRenderer(None) renderer = YAMLRenderer(None)
content = renderer.render(obj, 'application/yaml') content = renderer.render(obj, 'application/yaml')
self.assertEquals(content, _yaml_repr) self.assertEquals(content, _yaml_repr)
def test_render_and_parse(self): def test_render_and_parse(self):
""" """
Test rendering and then parsing returns the original object. Test rendering and then parsing returns the original object.
IE obj -> render -> parse -> obj. IE obj -> render -> parse -> obj.
""" """
obj = {'foo':['bar','baz']} obj = {'foo': ['bar', 'baz']}
renderer = YAMLRenderer(None) renderer = YAMLRenderer(None)
parser = YAMLParser(None) parser = YAMLParser(None)
...@@ -229,7 +268,6 @@ if YAMLRenderer: ...@@ -229,7 +268,6 @@ if YAMLRenderer:
self.assertEquals(obj, data) self.assertEquals(obj, data)
class XMLRendererTestCase(TestCase): class XMLRendererTestCase(TestCase):
""" """
Tests specific to the XML Renderer Tests specific to the XML Renderer
...@@ -285,7 +323,6 @@ class XMLRendererTestCase(TestCase): ...@@ -285,7 +323,6 @@ class XMLRendererTestCase(TestCase):
content = renderer.render({'field': None}, 'application/xml') content = renderer.render({'field': None}, 'application/xml')
self.assertXMLContains(content, '<field></field>') self.assertXMLContains(content, '<field></field>')
def assertXMLContains(self, xml, string): def assertXMLContains(self, xml, string):
self.assertTrue(xml.startswith('<?xml version="1.0" encoding="utf-8"?>\n<root>')) self.assertTrue(xml.startswith('<?xml version="1.0" encoding="utf-8"?>\n<root>'))
self.assertTrue(xml.endswith('</root>')) self.assertTrue(xml.endswith('</root>'))
......
Blog Posts API Blog Posts API
============== ==============
* http://api.django-rest-framework.org/blog-post/ * http://rest.ep.io/blog-post/
The models The models
---------- ----------
......
...@@ -5,11 +5,11 @@ Getting Started - Model Views ...@@ -5,11 +5,11 @@ Getting Started - Model Views
A live sandbox instance of this API is available: A live sandbox instance of this API is available:
http://api.django-rest-framework.org/model-resource-example/ http://rest.ep.io/model-resource-example/
You can browse the API using a web browser, or from the command line:: You can browse the API using a web browser, or from the command line::
curl -X GET http://api.django-rest-framework.org/resource-example/ -H 'Accept: text/plain' curl -X GET http://rest.ep.io/resource-example/ -H 'Accept: text/plain'
Often you'll want parts of your API to directly map to existing django models. Django REST framework handles this nicely for you in a couple of ways: Often you'll want parts of your API to directly map to existing django models. Django REST framework handles this nicely for you in a couple of ways:
...@@ -41,16 +41,16 @@ And we're done. We've now got a fully browseable API, which supports multiple i ...@@ -41,16 +41,16 @@ And we're done. We've now got a fully browseable API, which supports multiple i
We can visit the API in our browser: We can visit the API in our browser:
* http://api.django-rest-framework.org/model-resource-example/ * http://rest.ep.io/model-resource-example/
Or access it from the command line using curl: Or access it from the command line using curl:
.. code-block:: bash .. code-block:: bash
# Demonstrates API's input validation using form input # Demonstrates API's input validation using form input
bash: curl -X POST --data 'foo=true' http://api.django-rest-framework.org/model-resource-example/ bash: curl -X POST --data 'foo=true' http://rest.ep.io/model-resource-example/
{"detail": {"bar": ["This field is required."], "baz": ["This field is required."]}} {"detail": {"bar": ["This field is required."], "baz": ["This field is required."]}}
# Demonstrates API's input validation using JSON input # Demonstrates API's input validation using JSON input
bash: curl -X POST -H 'Content-Type: application/json' --data-binary '{"foo":true}' http://api.django-rest-framework.org/model-resource-example/ bash: curl -X POST -H 'Content-Type: application/json' --data-binary '{"foo":true}' http://rest.ep.io/model-resource-example/
{"detail": {"bar": ["This field is required."], "baz": ["This field is required."]}} {"detail": {"bar": ["This field is required."], "baz": ["This field is required."]}}
Object Store API Object Store API
================ ================
* http://api.django-rest-framework.org/object-store/ * http://rest.ep.io/object-store/
This example shows an object store API that can be used to store arbitrary serializable content. This example shows an object store API that can be used to store arbitrary serializable content.
......
...@@ -6,11 +6,11 @@ We're going to provide a simple wrapper around the awesome `pygments <http://pyg ...@@ -6,11 +6,11 @@ We're going to provide a simple wrapper around the awesome `pygments <http://pyg
.. note:: .. note::
A live sandbox instance of this API is available at http://api.django-rest-framework.org/pygments/ A live sandbox instance of this API is available at http://rest.ep.io/pygments/
You can browse the API using a web browser, or from the command line:: You can browse the API using a web browser, or from the command line::
curl -X GET http://api.django-rest-framework.org/pygments/ -H 'Accept: text/plain' curl -X GET http://rest.ep.io/pygments/ -H 'Accept: text/plain'
URL configuration URL configuration
...@@ -77,13 +77,13 @@ For example if we make a POST request using form input: ...@@ -77,13 +77,13 @@ For example if we make a POST request using form input:
.. code-block:: bash .. code-block:: bash
bash: curl -X POST --data 'code=print "hello, world!"' --data 'style=foobar' -H 'X-Requested-With: XMLHttpRequest' http://api.django-rest-framework.org/pygments/ bash: curl -X POST --data 'code=print "hello, world!"' --data 'style=foobar' -H 'X-Requested-With: XMLHttpRequest' http://rest.ep.io/pygments/
{"detail": {"style": ["Select a valid choice. foobar is not one of the available choices."], "lexer": ["This field is required."]}} {"detail": {"style": ["Select a valid choice. foobar is not one of the available choices."], "lexer": ["This field is required."]}}
Or if we make the same request using JSON: Or if we make the same request using JSON:
.. code-block:: bash .. code-block:: bash
bash: curl -X POST --data-binary '{"code":"print \"hello, world!\"", "style":"foobar"}' -H 'Content-Type: application/json' -H 'X-Requested-With: XMLHttpRequest' http://api.django-rest-framework.org/pygments/ bash: curl -X POST --data-binary '{"code":"print \"hello, world!\"", "style":"foobar"}' -H 'Content-Type: application/json' -H 'X-Requested-With: XMLHttpRequest' http://rest.ep.io/pygments/
{"detail": {"style": ["Select a valid choice. foobar is not one of the available choices."], "lexer": ["This field is required."]}} {"detail": {"style": ["Select a valid choice. foobar is not one of the available choices."], "lexer": ["This field is required."]}}
...@@ -5,11 +5,11 @@ Getting Started - Views ...@@ -5,11 +5,11 @@ Getting Started - Views
A live sandbox instance of this API is available: A live sandbox instance of this API is available:
http://api.django-rest-framework.org/resource-example/ http://rest.ep.io/resource-example/
You can browse the API using a web browser, or from the command line:: You can browse the API using a web browser, or from the command line::
curl -X GET http://api.django-rest-framework.org/resource-example/ -H 'Accept: text/plain' curl -X GET http://rest.ep.io/resource-example/ -H 'Accept: text/plain'
We're going to start off with a simple example, that demonstrates a few things: We're going to start off with a simple example, that demonstrates a few things:
...@@ -41,16 +41,16 @@ Now we'll write our views. The first is a read only view that links to three in ...@@ -41,16 +41,16 @@ Now we'll write our views. The first is a read only view that links to three in
That's us done. Our API now provides both programmatic access using JSON and XML, as well a nice browseable HTML view, so we can now access it both from the browser: That's us done. Our API now provides both programmatic access using JSON and XML, as well a nice browseable HTML view, so we can now access it both from the browser:
* http://api.django-rest-framework.org/resource-example/ * http://rest.ep.io/resource-example/
And from the command line: And from the command line:
.. code-block:: bash .. code-block:: bash
# Demonstrates API's input validation using form input # Demonstrates API's input validation using form input
bash: curl -X POST --data 'foo=true' http://api.django-rest-framework.org/resource-example/1/ bash: curl -X POST --data 'foo=true' http://rest.ep.io/resource-example/1/
{"detail": {"bar": ["This field is required."], "baz": ["This field is required."]}} {"detail": {"bar": ["This field is required."], "baz": ["This field is required."]}}
# Demonstrates API's input validation using JSON input # Demonstrates API's input validation using JSON input
bash: curl -X POST -H 'Content-Type: application/json' --data-binary '{"foo":true}' http://api.django-rest-framework.org/resource-example/1/ bash: curl -X POST -H 'Content-Type: application/json' --data-binary '{"foo":true}' http://rest.ep.io/resource-example/1/
{"detail": {"bar": ["This field is required."], "baz": ["This field is required."]}} {"detail": {"bar": ["This field is required."], "baz": ["This field is required."]}}
...@@ -9,11 +9,11 @@ a browseable Web API, and much of the other goodness that Django REST framework ...@@ -9,11 +9,11 @@ a browseable Web API, and much of the other goodness that Django REST framework
A live sandbox instance of this API is available for testing: A live sandbox instance of this API is available for testing:
* http://api.django-rest-framework.org/mixin/ * http://rest.ep.io/mixin/
You can browse the API using a web browser, or from the command line:: You can browse the API using a web browser, or from the command line::
curl -X GET http://api.django-rest-framework.org/mixin/ curl -X GET http://rest.ep.io/mixin/
URL configuration URL configuration
......
...@@ -11,11 +11,11 @@ Introduction ...@@ -11,11 +11,11 @@ Introduction
Django REST framework is a lightweight REST framework for Django, that aims to make it easy to build well-connected, self-describing RESTful Web APIs. Django REST framework is a lightweight REST framework for Django, that aims to make it easy to build well-connected, self-describing RESTful Web APIs.
**Browse example APIs created with Django REST framework:** `The Sandbox <http://api.django-rest-framework.org/>`_ **Browse example APIs created with Django REST framework:** `The Sandbox <http://rest.ep.io/>`_
Features: Features:
* Automatically provides an awesome Django admin style `browse-able self-documenting API <http://api.django-rest-framework.org>`_. * Automatically provides an awesome Django admin style `browse-able self-documenting API <http://rest.ep.io>`_.
* Clean, simple, views for Resources, using Django's new `class based views <http://docs.djangoproject.com/en/dev/topics/class-based-views/>`_. * Clean, simple, views for Resources, using Django's new `class based views <http://docs.djangoproject.com/en/dev/topics/class-based-views/>`_.
* Support for ModelResources with out-of-the-box default implementations and input validation. * Support for ModelResources with out-of-the-box default implementations and input validation.
* Pluggable :mod:`.parsers`, :mod:`renderers`, :mod:`authentication` and :mod:`permissions` - Easy to customise. * Pluggable :mod:`.parsers`, :mod:`renderers`, :mod:`authentication` and :mod:`permissions` - Easy to customise.
...@@ -101,7 +101,7 @@ There are a few real world web API examples included with Django REST framework. ...@@ -101,7 +101,7 @@ There are a few real world web API examples included with Django REST framework.
All the examples are freely available for testing in the sandbox: All the examples are freely available for testing in the sandbox:
http://api.django-rest-framework.org http://rest.ep.io
(The :doc:`examples/sandbox` resource is also documented.) (The :doc:`examples/sandbox` resource is also documented.)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment