Commit 497da7fc by Tom Christie

Clean up field initialization. Fixes #497

parent 628e3bf0
...@@ -100,7 +100,8 @@ class BaseSerializer(Field): ...@@ -100,7 +100,8 @@ class BaseSerializer(Field):
_options_class = SerializerOptions _options_class = SerializerOptions
_dict_class = SortedDictWithMetadata # Set to unsorted dict for backwards compatibility with unsorted implementations. _dict_class = SortedDictWithMetadata # Set to unsorted dict for backwards compatibility with unsorted implementations.
def __init__(self, instance=None, data=None, files=None, context=None, partial=False, **kwargs): def __init__(self, instance=None, data=None, files=None,
context=None, partial=False, **kwargs):
super(BaseSerializer, self).__init__(**kwargs) super(BaseSerializer, self).__init__(**kwargs)
self.opts = self._options_class(self.Meta) self.opts = self._options_class(self.Meta)
self.parent = None self.parent = None
...@@ -151,8 +152,6 @@ class BaseSerializer(Field): ...@@ -151,8 +152,6 @@ class BaseSerializer(Field):
base_fields = copy.deepcopy(self.base_fields) base_fields = copy.deepcopy(self.base_fields)
for key, field in base_fields.items(): for key, field in base_fields.items():
ret[key] = field ret[key] = field
# Set up the field
field.initialize(parent=self, field_name=key)
# Add in the default fields # Add in the default fields
default_fields = self.get_default_fields() default_fields = self.get_default_fields()
...@@ -172,6 +171,10 @@ class BaseSerializer(Field): ...@@ -172,6 +171,10 @@ class BaseSerializer(Field):
for key in self.opts.exclude: for key in self.opts.exclude:
ret.pop(key, None) ret.pop(key, None)
# Initialize the fields
for key, field in ret.items():
field.initialize(parent=self, field_name=key)
return ret return ret
##### #####
...@@ -186,6 +189,13 @@ class BaseSerializer(Field): ...@@ -186,6 +189,13 @@ class BaseSerializer(Field):
if parent.opts.depth: if parent.opts.depth:
self.opts.depth = parent.opts.depth - 1 self.opts.depth = parent.opts.depth - 1
# We need to call initialize here to ensure any nested
# serializers that will have already called initialize on their
# descendants get updated with *their* parent.
# We could be a bit more smart about this, but it'll do for now.
for key, field in self.fields.items():
field.initialize(parent=self, field_name=key)
##### #####
# Methods to convert or revert from objects <--> primitive representations. # Methods to convert or revert from objects <--> primitive representations.
......
...@@ -4,7 +4,7 @@ from django.test import TestCase ...@@ -4,7 +4,7 @@ from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel, from rest_framework.tests.models import (Album, ActionItem, Anchor, BasicModel,
BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel, BlankFieldModel, BlogPost, Book, CallableDefaultValueModel, DefaultValueModel,
ManyToManyModel, Person, ReadOnlyManyToManyModel) ManyToManyModel, Person, ReadOnlyManyToManyModel, Photo)
class SubComment(object): class SubComment(object):
...@@ -764,3 +764,55 @@ class DepthTest(TestCase): ...@@ -764,3 +764,55 @@ class DepthTest(TestCase):
'writer': {'id': 1, 'name': u'django', 'age': 1}} 'writer': {'id': 1, 'name': u'django', 'age': 1}}
self.assertEqual(serializer.data, expected) self.assertEqual(serializer.data, expected)
class NestedSerializerContextTests(TestCase):
def test_nested_serializer_context(self):
"""
Regression for #497
https://github.com/tomchristie/django-rest-framework/issues/497
"""
class PhotoSerializer(serializers.ModelSerializer):
class Meta:
model = Photo
fields = ("description", "callable")
callable = serializers.SerializerMethodField('_callable')
def _callable(self, instance):
if not 'context_item' in self.context:
raise RuntimeError("context isn't getting passed into 2nd level nested serializer")
return "success"
class AlbumSerializer(serializers.ModelSerializer):
class Meta:
model = Album
fields = ("photo_set", "callable")
photo_set = PhotoSerializer(source="photo_set")
callable = serializers.SerializerMethodField("_callable")
def _callable(self, instance):
if not 'context_item' in self.context:
raise RuntimeError("context isn't getting passed into 1st level nested serializer")
return "success"
class AlbumCollection(object):
albums = None
class AlbumCollectionSerializer(serializers.Serializer):
albums = AlbumSerializer(source="albums")
album1 = Album.objects.create(title="album 1")
album2 = Album.objects.create(title="album 2")
Photo.objects.create(description="Bigfoot", album=album1)
Photo.objects.create(description="Unicorn", album=album1)
Photo.objects.create(description="Yeti", album=album2)
Photo.objects.create(description="Sasquatch", album=album2)
album_collection = AlbumCollection()
album_collection.albums = [album1, album2]
# This will raise RuntimeError if context doesn't get passed correctly to the nested Serializers
AlbumCollectionSerializer(album_collection, context={'context_item': 'album context'}).data
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