Merge with master

This commit is contained in:
Tom Christie 2012-04-11 15:28:57 +01:00
commit 44df8345f3
8 changed files with 38 additions and 31 deletions

View File

@ -34,6 +34,7 @@ Paul Oswald <poswald>
Sean C. Farley <scfarley> Sean C. Farley <scfarley>
Daniel Izquierdo <izquierdo> Daniel Izquierdo <izquierdo>
Can Yavuz <tschan> Can Yavuz <tschan>
Shawn Lewis <shawnlewis>
THANKS TO: THANKS TO:

View File

@ -104,7 +104,7 @@ class YAMLParser(BaseParser):
""" """
try: try:
return (yaml.safe_load(stream), None) return (yaml.safe_load(stream), None)
except ValueError, exc: except (ValueError, yaml.parser.ParserError), exc:
raise ImmediateResponse( raise ImmediateResponse(
{'detail': 'YAML parse error - %s' % unicode(exc)}, {'detail': 'YAML parse error - %s' % unicode(exc)},
status=status.HTTP_400_BAD_REQUEST) status=status.HTTP_400_BAD_REQUEST)

View File

@ -25,16 +25,9 @@ def _field_to_tuple(field):
def _fields_to_list(fields): def _fields_to_list(fields):
""" """
Return a list of field names. Return a list of field tuples.
""" """
return [_field_to_tuple(field)[0] for field in fields or ()] return [_field_to_tuple(field) for field in fields or ()]
def _fields_to_dict(fields):
"""
Return a `dict` of field name -> None, or tuple of fields, or Serializer class
"""
return dict([_field_to_tuple(field) for field in fields or ()])
class _SkipField(Exception): class _SkipField(Exception):
@ -110,9 +103,6 @@ class Serializer(object):
self.stack = stack self.stack = stack
def get_fields(self, obj): def get_fields(self, obj):
"""
Return the set of field names/keys to use for a model instance/dict.
"""
fields = self.fields fields = self.fields
# If `fields` is not set, we use the default fields and modify # If `fields` is not set, we use the default fields and modify
@ -123,9 +113,6 @@ class Serializer(object):
exclude = self.exclude or () exclude = self.exclude or ()
fields = set(default + list(include)) - set(exclude) fields = set(default + list(include)) - set(exclude)
else:
fields = _fields_to_list(self.fields)
return fields return fields
def get_default_fields(self, obj): def get_default_fields(self, obj):
@ -139,9 +126,7 @@ class Serializer(object):
else: else:
return obj.keys() return obj.keys()
def get_related_serializer(self, key): def get_related_serializer(self, info):
info = _fields_to_dict(self.fields).get(key, None)
# If an element in `fields` is a 2-tuple of (str, tuple) # If an element in `fields` is a 2-tuple of (str, tuple)
# then the second element of the tuple is the fields to # then the second element of the tuple is the fields to
# set on the related serializer # set on the related serializer
@ -175,11 +160,11 @@ class Serializer(object):
""" """
return self.rename.get(smart_str(key), smart_str(key)) return self.rename.get(smart_str(key), smart_str(key))
def serialize_val(self, key, obj): def serialize_val(self, key, obj, related_info):
""" """
Convert a model field or dict value into a serializable representation. Convert a model field or dict value into a serializable representation.
""" """
related_serializer = self.get_related_serializer(key) related_serializer = self.get_related_serializer(related_info)
if self.depth is None: if self.depth is None:
depth = None depth = None
@ -219,7 +204,7 @@ class Serializer(object):
fields = self.get_fields(instance) fields = self.get_fields(instance)
# serialize each required field # serialize each required field
for fname in fields: for fname, related_info in _fields_to_list(fields):
try: try:
# we first check for a method 'fname' on self, # we first check for a method 'fname' on self,
# 'fname's signature must be 'def fname(self, instance)' # 'fname's signature must be 'def fname(self, instance)'
@ -237,7 +222,7 @@ class Serializer(object):
continue continue
key = self.serialize_key(fname) key = self.serialize_key(fname)
val = self.serialize_val(fname, obj) val = self.serialize_val(fname, obj, related_info)
data[key] = val data[key] = val
except _SkipField: except _SkipField:
pass pass

View File

@ -104,6 +104,27 @@ class TestFieldNesting(TestCase):
self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}}) self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}})
self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}}) self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}})
def test_serializer_no_fields(self):
"""
Test related serializer works when the fields attr isn't present. Fix for
#178.
"""
class NestedM2(Serializer):
fields = ('field1', )
class NestedM3(Serializer):
fields = ('field2', )
class SerializerM2(Serializer):
include = [('field', NestedM2)]
exclude = ('id', )
class SerializerM3(Serializer):
fields = [('field', NestedM3)]
self.assertEqual(SerializerM2().serialize(self.m2), {'field': {'field1': u'foo'}})
self.assertEqual(SerializerM3().serialize(self.m3), {'field': {'field2': u'bar'}})
def test_serializer_classname_nesting(self): def test_serializer_classname_nesting(self):
""" """
Test related model serialization Test related model serialization

View File

@ -9,7 +9,6 @@ from djangorestframework.request import Request
import re import re
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
MSIE_USER_AGENT_REGEX = re.compile(r'^Mozilla/[0-9]+\.[0-9]+ \([^)]*; MSIE [0-9]+\.[0-9]+[a-z]?;[^)]*\)(?!.* Opera )') MSIE_USER_AGENT_REGEX = re.compile(r'^Mozilla/[0-9]+\.[0-9]+ \([^)]*; MSIE [0-9]+\.[0-9]+[a-z]?;[^)]*\)(?!.* Opera )')

View File

@ -49,6 +49,7 @@ YAML
YAML support is optional, and requires `PyYAML`_. YAML support is optional, and requires `PyYAML`_.
Login / Logout Login / Logout
-------------- --------------

View File

@ -1,6 +1,6 @@
# Documentation requires Django & Sphinx, and their dependencies... # Documentation requires Django & Sphinx, and their dependencies...
Django==1.2.4 Django>=1.2.4
Jinja2==2.5.5 Jinja2==2.5.5
Pygments==1.4 Pygments==1.4
Sphinx==1.0.7 Sphinx==1.0.7

View File

@ -9,15 +9,15 @@ from django.conf.urls.defaults import patterns, url
class ExampleView(ResponseMixin, View): class ExampleView(ResponseMixin, View):
"""An example view using Django 1.3's class based views. """An example view using Django 1.3's class based views.
Uses djangorestframework's RendererMixin to provide support for multiple output formats.""" Uses djangorestframework's RendererMixin to provide support for multiple
output formats."""
renderers = DEFAULT_RENDERERS renderers = DEFAULT_RENDERERS
def get(self, request): def get(self, request):
url = reverse('mixin-view', request) url = reverse('mixin-view', request=request)
response = Response({'description': 'Some example content', response = Response(200, {'description': 'Some example content',
'url': url}, status=200) 'url': url})
self.response = self.prepare_response(response) return self.render(response)
return self.response
urlpatterns = patterns('', urlpatterns = patterns('',