mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-02 20:54:42 +03:00
Documentation for parsers
This commit is contained in:
parent
7a89d7a770
commit
551c86c43a
|
@ -8,17 +8,144 @@ sending more complex data than simple forms
|
|||
>
|
||||
> — Malcom Tredinnick, [Django developers group][cite]
|
||||
|
||||
REST framework includes a number of built in Parser classes, that allow you to accept requests with various media types. There is also support for defining your own custom parsers, which gives you the flexiblity to design the media types that your API accepts.
|
||||
|
||||
## How the parser is determined
|
||||
|
||||
The set of valid parsers for a view is always defined as a list of classes. When either `request.DATA` or `request.FILES` is accessed, REST framework will examine the `Content-Type` header on the incoming request, and determine which parser to use to parse the request content.
|
||||
|
||||
## Setting the parsers
|
||||
|
||||
The default set of parsers may be set globally, using the `DEFAULT_PARSERS` setting. For example, the following settings would allow requests with `YAML` content.
|
||||
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PARSERS': (
|
||||
'rest_framework.parsers.YAMLParser',
|
||||
)
|
||||
}
|
||||
|
||||
You can also set the renderers used for an individual view, using the `APIView` class based views.
|
||||
|
||||
class ExampleView(APIView):
|
||||
"""
|
||||
A view that can accept POST requests with YAML content.
|
||||
"""
|
||||
parser_classes = (YAMLParser,)
|
||||
|
||||
def post(self, request, format=None):
|
||||
return Response({'received data': request.DATA})
|
||||
|
||||
Or, if you're using the `@api_view` decorator with function based views.
|
||||
|
||||
@api_view(('POST',)),
|
||||
@parser_classes((YAMLParser,))
|
||||
def example_view(request, format=None):
|
||||
"""
|
||||
A view that can accept POST requests with YAML content.
|
||||
"""
|
||||
return Response({'received data': request.DATA})
|
||||
|
||||
---
|
||||
|
||||
# API Reference
|
||||
|
||||
## JSONParser
|
||||
|
||||
Parses `JSON` request content.
|
||||
|
||||
**.media_type**: `application/json`
|
||||
|
||||
## YAMLParser
|
||||
|
||||
Parses `YAML` request content.
|
||||
|
||||
**.media_type**: `application/yaml`
|
||||
|
||||
## XMLParser
|
||||
|
||||
Parses REST framework's default style of `XML` request content.
|
||||
|
||||
Note that the `XML` markup language is used typically used as the base language for more strictly defined domain-specific languages, such as `RSS`, `Atom`, `SOAP`, and `XHTML`.
|
||||
|
||||
If you are considering using `XML` for your API, you may want to consider implementing a custom renderer and parser for your specific requirements, and using an existing domain-specific media-type, or creating your own custom XML-based media-type.
|
||||
|
||||
**.media_type**: `application/xml`
|
||||
|
||||
## FormParser
|
||||
|
||||
Parses HTML form content. `request.DATA` will be populated with a `QueryDict` of data, `request.FILES` will be populated with an empty `QueryDict` of data.
|
||||
|
||||
You will typically want to use both `FormParser` and `MultiPartParser` together in order to fully support HTML form data.
|
||||
|
||||
**.media_type**: `application/x-www-form-urlencoded`
|
||||
|
||||
## MultiPartParser
|
||||
|
||||
## Custom parsers
|
||||
Parses multipart HTML form content, which supports file uploads. Both `request.DATA` and `request.FILES` will be populated with a `QueryDict`.
|
||||
|
||||
You will typically want to use both `FormParser` and `MultiPartParser` together in order to fully support HTML form data.
|
||||
|
||||
**.media_type**: `multipart/form-data`
|
||||
|
||||
---
|
||||
|
||||
# Custom parsers
|
||||
|
||||
To implement a custom parser, you should override `BaseParser`, set the `.media_type` property, and implement the `.parse_stream(self, stream, parser_context)` method.
|
||||
|
||||
The method should return the data that will be used to populate the `request.DATA` property.
|
||||
|
||||
For example:
|
||||
|
||||
class PlainTextParser(BaseParser):
|
||||
"""
|
||||
Plain text parser.
|
||||
"""
|
||||
|
||||
media_type = 'text/plain'
|
||||
|
||||
def parse_stream(self, stream, parser_context=None):
|
||||
"""
|
||||
Simply return a string representing the body of the request.
|
||||
"""
|
||||
return stream.read()
|
||||
|
||||
The arguments passed to `.parse_stream()` are:
|
||||
|
||||
### stream
|
||||
|
||||
A stream-like object representing the body of the request.
|
||||
|
||||
### parser_context
|
||||
|
||||
If supplied, this argument will be a dictionary containing any additional context that may be required to parse the request content. By default it includes the keys `'upload_handlers'` and `'meta'`, which contain the values of the `request.upload_handlers` and `request.meta` properties.
|
||||
|
||||
## Uploading file content
|
||||
|
||||
If your custom parser needs to support file uploads, you may return a `DataAndFiles` object from the `.parse_stream()` method. `DataAndFiles` should be instantiated with two arguments. The first argument will be used to populate the `request.DATA` property, and the second argument will be used to populate the `request.FILES` property.
|
||||
|
||||
For example:
|
||||
|
||||
class SimpleFileUploadParser(BaseParser):
|
||||
"""
|
||||
A naive raw file upload parser.
|
||||
"""
|
||||
|
||||
def parse_stream(self, stream, parser_context):
|
||||
content = stream.read()
|
||||
name = 'example.dat'
|
||||
content_type = 'application/octet-stream'
|
||||
size = len(content)
|
||||
charset = 'utf-8'
|
||||
|
||||
# Write a temporary file based on the request content
|
||||
temp = tempfile.NamedTemporaryFile(delete=False)
|
||||
temp.write(content)
|
||||
uploaded = UploadedFile(temp, name, content_type, size, charset)
|
||||
|
||||
# Return the uploaded file
|
||||
data = {}
|
||||
files = {name: uploaded}
|
||||
return DataAndFiles(data, files)
|
||||
|
||||
[cite]: https://groups.google.com/d/topic/django-developers/dxI4qVzrBY4/discussion
|
||||
|
|
|
@ -42,8 +42,8 @@ You can also set the renderers used for an individual view, using the `APIView`
|
|||
|
||||
Or, if you're using the `@api_view` decorator with function based views.
|
||||
|
||||
@api_view('GET'),
|
||||
@renderer_classes(JSONRenderer, JSONPRenderer)
|
||||
@api_view(('GET',)),
|
||||
@renderer_classes((JSONRenderer, JSONPRenderer))
|
||||
def user_count_view(request, format=None):
|
||||
"""
|
||||
A view that returns the count of active users, in JSON or JSONp.
|
||||
|
@ -66,27 +66,45 @@ If your API includes views that can serve both regular webpages and API response
|
|||
|
||||
## JSONRenderer
|
||||
|
||||
**.media_type:** `application/json`
|
||||
Renders the request data into `JSON`.
|
||||
|
||||
**.format:** `'.json'`
|
||||
The client may additionally include an `'indent'` media type parameter, in which case the returned `JSON` will be indented. For example `Accept: application/json; indent=4`.
|
||||
|
||||
**.media_type**: `application/json`
|
||||
|
||||
**.format**: `'.json'`
|
||||
|
||||
## JSONPRenderer
|
||||
|
||||
**.media_type:** `application/javascript`
|
||||
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.
|
||||
|
||||
**.format:** `'.jsonp'`
|
||||
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'`.
|
||||
|
||||
**Note**: If you require cross-domain AJAX requests, you may also want to consider using [CORS] as an alternative to `JSONP`.
|
||||
|
||||
**.media_type**: `application/javascript`
|
||||
|
||||
**.format**: `'.jsonp'`
|
||||
|
||||
## YAMLRenderer
|
||||
|
||||
**.media_type:** `application/yaml`
|
||||
Renders the request data into `YAML`.
|
||||
|
||||
**.format:** `'.yaml'`
|
||||
**.media_type**: `application/yaml`
|
||||
|
||||
**.format**: `'.yaml'`
|
||||
|
||||
## XMLRenderer
|
||||
|
||||
**.media_type:** `application/xml`
|
||||
Renders REST framework's default style of `XML` response content.
|
||||
|
||||
**.format:** `'.xml'`
|
||||
Note that the `XML` markup language is used typically used as the base language for more strictly defined domain-specific languages, such as `RSS`, `Atom`, `SOAP`, and `XHTML`.
|
||||
|
||||
If you are considering using `XML` for your API, you may want to consider implementing a custom renderer and parser for your specific requirements, and using an existing domain-specific media-type, or creating your own custom XML-based media-type.
|
||||
|
||||
**.media_type**: `application/xml`
|
||||
|
||||
**.format**: `'.xml'`
|
||||
|
||||
## HTMLRenderer
|
||||
|
||||
|
@ -118,19 +136,21 @@ You can use `HTMLRenderer` either to return regular HTML pages using REST framew
|
|||
|
||||
If you're building websites that use `HTMLRenderer` along with other renderer classes, you should consider listing `HTMLRenderer` as the first class in the `renderer_classes` list, so that it will be prioritised first even for browsers that send poorly formed `ACCEPT:` headers.
|
||||
|
||||
**.media_type:** `text/html`
|
||||
**.media_type**: `text/html`
|
||||
|
||||
**.format:** `'.html'`
|
||||
**.format**: `'.html'`
|
||||
|
||||
## BrowsableAPIRenderer
|
||||
|
||||
Renders data into HTML for the Browseable API. This renderer will determine which other renderer would have been given highest priority, and use that to display an API style response within the HTML page.
|
||||
|
||||
**.media_type:** `text/html`
|
||||
**.media_type**: `text/html`
|
||||
|
||||
**.format:** `'.api'`
|
||||
**.format**: `'.api'`
|
||||
|
||||
## Custom renderers
|
||||
---
|
||||
|
||||
# Custom renderers
|
||||
|
||||
To implement a custom renderer, you should override `BaseRenderer`, set the `.media_type` and `.format` properties, and implement the `.render(self, data, media_type=None, renderer_context=None)` method.
|
||||
|
||||
|
@ -151,15 +171,15 @@ For example:
|
|||
|
||||
The arguments passed to the `.render()` method are:
|
||||
|
||||
#### `data`
|
||||
### `data`
|
||||
|
||||
The request data, as set by the `Response()` instantiation.
|
||||
|
||||
#### `media_type=None`
|
||||
### `media_type=None`
|
||||
|
||||
Optional. If provided, this is the accepted media type, as determined by the content negotiation stage. Depending on the client's `Accept:` header, this may be more specific than the renderer's `media_type` attribute, and may include media type parameters. For example `"application/json; nested=true"`.
|
||||
|
||||
#### `renderer_context=None`
|
||||
### `renderer_context=None`
|
||||
|
||||
Optional. If provided, this is a dictionary of contextual information provided by the view.
|
||||
By default this will include the following keys: `view`, `request`, `response`, `args`, `kwargs`.
|
||||
|
@ -213,6 +233,7 @@ For good examples of custom media types, see GitHub's use of a custom [applicati
|
|||
[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
|
||||
[CORS]: http://en.wikipedia.org/wiki/Cross-origin_resource_sharing
|
||||
[HATEOAS]: http://timelessrepo.com/haters-gonna-hateoas
|
||||
[quote]: http://roy.gbiv.com/untangled/2008/rest-apis-must-be-hypertext-driven
|
||||
[application/vnd.github+json]: http://developer.github.com/v3/media/
|
||||
|
|
|
@ -45,6 +45,8 @@ You won't typically need to access this property.
|
|||
|
||||
**Note:** If a client sends malformed content, then accessing `request.DATA` or `request.FILES` may raise a `ParseError`. By default REST framework's `APIView` class or `@api_view` decorator will catch the error and return a `400 Bad Request` response.
|
||||
|
||||
If a client sends a request with a content-type that cannot be parsed then a `UnsupportedMediaType` exception will be raised, which by default will be caught and return a `415 Unsupported Media Type` response.
|
||||
|
||||
---
|
||||
|
||||
# Authentication
|
||||
|
|
|
@ -98,23 +98,6 @@ class YAMLParser(BaseParser):
|
|||
raise ParseError('YAML parse error - %s' % unicode(exc))
|
||||
|
||||
|
||||
class PlainTextParser(BaseParser):
|
||||
"""
|
||||
Plain text parser.
|
||||
"""
|
||||
|
||||
media_type = 'text/plain'
|
||||
|
||||
def parse_stream(self, stream, **opts):
|
||||
"""
|
||||
Returns a 2-tuple of `(data, files)`.
|
||||
|
||||
`data` will simply be a string representing the body of the request.
|
||||
`files` will always be `None`.
|
||||
"""
|
||||
return stream.read()
|
||||
|
||||
|
||||
class FormParser(BaseParser):
|
||||
"""
|
||||
Parser for form data.
|
||||
|
|
|
@ -10,9 +10,9 @@ from rest_framework import status
|
|||
from rest_framework.authentication import SessionAuthentication
|
||||
from django.test.client import RequestFactory
|
||||
from rest_framework.parsers import (
|
||||
BaseParser,
|
||||
FormParser,
|
||||
MultiPartParser,
|
||||
PlainTextParser,
|
||||
JSONParser
|
||||
)
|
||||
from rest_framework.request import Request
|
||||
|
@ -24,6 +24,19 @@ from rest_framework.views import APIView
|
|||
factory = RequestFactory()
|
||||
|
||||
|
||||
class PlainTextParser(BaseParser):
|
||||
media_type = 'text/plain'
|
||||
|
||||
def parse_stream(self, stream, **opts):
|
||||
"""
|
||||
Returns a 2-tuple of `(data, files)`.
|
||||
|
||||
`data` will simply be a string representing the body of the request.
|
||||
`files` will always be `None`.
|
||||
"""
|
||||
return stream.read()
|
||||
|
||||
|
||||
class TestMethodOverloading(TestCase):
|
||||
def test_method(self):
|
||||
"""
|
||||
|
|
Loading…
Reference in New Issue
Block a user