mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-02-03 13:14:30 +03:00
Parsers may return raw data, or a DataAndFiles object
This commit is contained in:
parent
d180e984e9
commit
7abef9ac3b
|
@ -36,6 +36,12 @@ __all__ = (
|
|||
)
|
||||
|
||||
|
||||
class DataAndFiles(object):
|
||||
def __init__(self, data, files):
|
||||
self.data = data
|
||||
self.files = files
|
||||
|
||||
|
||||
class BaseParser(object):
|
||||
"""
|
||||
All parsers should extend :class:`BaseParser`, specifying a :attr:`media_type` attribute,
|
||||
|
@ -80,7 +86,7 @@ class JSONParser(BaseParser):
|
|||
`files` will always be `None`.
|
||||
"""
|
||||
try:
|
||||
return (json.load(stream), None)
|
||||
return json.load(stream)
|
||||
except ValueError, exc:
|
||||
raise ParseError('JSON parse error - %s' % unicode(exc))
|
||||
|
||||
|
@ -100,7 +106,7 @@ class YAMLParser(BaseParser):
|
|||
`files` will always be `None`.
|
||||
"""
|
||||
try:
|
||||
return (yaml.safe_load(stream), None)
|
||||
return yaml.safe_load(stream)
|
||||
except (ValueError, yaml.parser.ParserError), exc:
|
||||
raise ParseError('YAML parse error - %s' % unicode(exc))
|
||||
|
||||
|
@ -119,7 +125,7 @@ class PlainTextParser(BaseParser):
|
|||
`data` will simply be a string representing the body of the request.
|
||||
`files` will always be `None`.
|
||||
"""
|
||||
return (stream.read(), None)
|
||||
return stream.read()
|
||||
|
||||
|
||||
class FormParser(BaseParser):
|
||||
|
@ -137,7 +143,7 @@ class FormParser(BaseParser):
|
|||
`files` will always be :const:`None`.
|
||||
"""
|
||||
data = QueryDict(stream.read())
|
||||
return (data, None)
|
||||
return data
|
||||
|
||||
|
||||
class MultiPartParser(BaseParser):
|
||||
|
@ -149,16 +155,17 @@ class MultiPartParser(BaseParser):
|
|||
|
||||
def parse(self, stream, **opts):
|
||||
"""
|
||||
Returns a 2-tuple of `(data, files)`.
|
||||
Returns a DataAndFiles object.
|
||||
|
||||
`data` will be a :class:`QueryDict` containing all the form parameters.
|
||||
`files` will be a :class:`QueryDict` containing all the form files.
|
||||
`.data` will be a `QueryDict` containing all the form parameters.
|
||||
`.files` will be a `QueryDict` containing all the form files.
|
||||
"""
|
||||
meta = opts['meta']
|
||||
upload_handlers = opts['upload_handlers']
|
||||
try:
|
||||
parser = DjangoMultiPartParser(meta, stream, upload_handlers)
|
||||
return parser.parse()
|
||||
data, files = parser.parse()
|
||||
return DataAndFiles(data, files)
|
||||
except MultiPartParserError, exc:
|
||||
raise ParseError('Multipart form parse error - %s' % unicode(exc))
|
||||
|
||||
|
@ -171,19 +178,13 @@ class XMLParser(BaseParser):
|
|||
media_type = 'application/xml'
|
||||
|
||||
def parse(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`.
|
||||
"""
|
||||
try:
|
||||
tree = ET.parse(stream)
|
||||
except (ExpatError, ETParseError, ValueError), exc:
|
||||
raise ParseError('XML parse error - %s' % unicode(exc))
|
||||
data = self._xml_convert(tree.getroot())
|
||||
|
||||
return (data, None)
|
||||
return data
|
||||
|
||||
def _xml_convert(self, element):
|
||||
"""
|
||||
|
|
|
@ -146,7 +146,7 @@ class Request(object):
|
|||
self._load_method_and_content_type()
|
||||
|
||||
if not _hasattr(self, '_data'):
|
||||
(self._data, self._files) = self._parse()
|
||||
self._data, self._files = self._parse()
|
||||
|
||||
def _load_method_and_content_type(self):
|
||||
"""
|
||||
|
@ -201,11 +201,11 @@ class Request(object):
|
|||
self._CONTENTTYPE_PARAM in self._data):
|
||||
self._content_type = self._data.pop(self._CONTENTTYPE_PARAM)[0]
|
||||
self._stream = StringIO(self._data.pop(self._CONTENT_PARAM)[0])
|
||||
(self._data, self._files) = self._parse()
|
||||
self._data, self._files = self._parse()
|
||||
|
||||
def _parse(self):
|
||||
"""
|
||||
Parse the request content.
|
||||
Parse the request content, returning a two-tuple of (data, files)
|
||||
|
||||
May raise an `UnsupportedMediaType`, or `ParseError` exception.
|
||||
"""
|
||||
|
@ -214,8 +214,14 @@ class Request(object):
|
|||
|
||||
for parser in self.get_parsers():
|
||||
if parser.can_handle_request(self.content_type):
|
||||
return parser.parse(self.stream, meta=self.META,
|
||||
upload_handlers=self.upload_handlers)
|
||||
parsed = parser.parse(self.stream, meta=self.META,
|
||||
upload_handlers=self.upload_handlers)
|
||||
# Parser classes may return the raw data, or a
|
||||
# DataAndFiles object. Unpack the result as required.
|
||||
try:
|
||||
return (parsed.data, parsed.files)
|
||||
except AttributeError:
|
||||
return (parsed, None)
|
||||
|
||||
raise UnsupportedMediaType(self._content_type)
|
||||
|
||||
|
|
|
@ -153,7 +153,7 @@ class TestFormParser(TestCase):
|
|||
parser = FormParser()
|
||||
|
||||
stream = StringIO(self.string)
|
||||
(data, files) = parser.parse(stream)
|
||||
data = parser.parse(stream)
|
||||
|
||||
self.assertEqual(Form(data).is_valid(), True)
|
||||
|
||||
|
@ -203,10 +203,10 @@ class TestXMLParser(TestCase):
|
|||
|
||||
def test_parse(self):
|
||||
parser = XMLParser()
|
||||
(data, files) = parser.parse(self._input)
|
||||
data = parser.parse(self._input)
|
||||
self.assertEqual(data, self._data)
|
||||
|
||||
def test_complex_data_parse(self):
|
||||
parser = XMLParser()
|
||||
(data, files) = parser.parse(self._complex_data_input)
|
||||
data = parser.parse(self._complex_data_input)
|
||||
self.assertEqual(data, self._complex_data)
|
||||
|
|
|
@ -301,7 +301,7 @@ if YAMLRenderer:
|
|||
parser = YAMLParser()
|
||||
|
||||
content = renderer.render(obj, 'application/yaml')
|
||||
(data, files) = parser.parse(StringIO(content))
|
||||
data = parser.parse(StringIO(content))
|
||||
self.assertEquals(obj, data)
|
||||
|
||||
|
||||
|
@ -392,7 +392,7 @@ class XMLRendererTestCase(TestCase):
|
|||
content = StringIO(renderer.render(self._complex_data, 'application/xml'))
|
||||
|
||||
parser = XMLParser()
|
||||
complex_data_out, dummy = parser.parse(content)
|
||||
complex_data_out = parser.parse(content)
|
||||
error_msg = "complex data differs!IN:\n %s \n\n OUT:\n %s" % (repr(self._complex_data), repr(complex_data_out))
|
||||
self.assertEqual(self._complex_data, complex_data_out, error_msg)
|
||||
|
||||
|
|
|
@ -4,7 +4,6 @@ Tests for content parsing, and form-overloaded content parsing.
|
|||
from django.conf.urls.defaults import patterns
|
||||
from django.contrib.auth.models import User
|
||||
from django.test import TestCase, Client
|
||||
from django.utils import simplejson as json
|
||||
|
||||
from djangorestframework import status
|
||||
from djangorestframework.authentication import UserLoggedInAuthentication
|
||||
|
@ -13,7 +12,6 @@ from djangorestframework.parsers import (
|
|||
FormParser,
|
||||
MultiPartParser,
|
||||
PlainTextParser,
|
||||
JSONParser
|
||||
)
|
||||
from djangorestframework.request import Request
|
||||
from djangorestframework.response import Response
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
"""
|
||||
Helper classes for parsers.
|
||||
"""
|
||||
import datetime
|
||||
import decimal
|
||||
from django.utils import timezone
|
||||
|
@ -6,10 +9,12 @@ from django.utils import simplejson as json
|
|||
|
||||
class JSONEncoder(json.JSONEncoder):
|
||||
"""
|
||||
JSONEncoder subclass that knows how to encode date/time and decimal types.
|
||||
JSONEncoder subclass that knows how to encode date/time,
|
||||
decimal types, and generators.
|
||||
"""
|
||||
def default(self, o):
|
||||
# See "Date Time String Format" in the ECMA-262 specification.
|
||||
# For Date Time string spec, see ECMA 262
|
||||
# http://ecma-international.org/ecma-262/5.1/#sec-15.9.1.15
|
||||
if isinstance(o, datetime.datetime):
|
||||
r = o.isoformat()
|
||||
if o.microsecond:
|
||||
|
|
|
@ -127,7 +127,7 @@ We've now got a few comment instances to play with. Let's take a look at serial
|
|||
|
||||
serializer = CommentSerializer(instance=c1)
|
||||
serializer.data
|
||||
# {'email': u'leila@example.com', 'content': u'nothing to say', 'created': datetime.datetime(2012, 8, 22, 16, 20, 9, 822774)}
|
||||
# {'email': u'leila@example.com', 'content': u'nothing to say', 'created': datetime.datetime(2012, 8, 22, 16, 20, 9, 822774, tzinfo=<UTC>)}
|
||||
|
||||
At this point we've translated the model instance into python native datatypes. To finalise the serialization process we render the data into `json`.
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user