Handle ObjectDoesNotExist exceptions when serializing null reverse one-to-one

This commit is contained in:
Mark Aaron Shirley 2013-01-04 21:11:03 +01:00
parent ad671022e1
commit 213981cef3
4 changed files with 44 additions and 10 deletions

View File

@ -100,7 +100,10 @@ class RelatedField(WritableField):
### Regular serializer stuff... ### Regular serializer stuff...
def field_to_native(self, obj, field_name): def field_to_native(self, obj, field_name):
try:
value = getattr(obj, self.source or field_name) value = getattr(obj, self.source or field_name)
except ObjectDoesNotExist:
return None
return self.to_native(value) return self.to_native(value)
def field_from_native(self, data, files, field_name, into): def field_from_native(self, data, files, field_name, into):
@ -202,7 +205,10 @@ class PrimaryKeyRelatedField(RelatedField):
pk = obj.serializable_value(self.source or field_name) pk = obj.serializable_value(self.source or field_name)
except AttributeError: except AttributeError:
# RelatedObject (reverse relationship) # RelatedObject (reverse relationship)
try:
obj = getattr(obj, self.source or field_name) obj = getattr(obj, self.source or field_name)
except ObjectDoesNotExist:
return None
return self.to_native(obj.pk) return self.to_native(obj.pk)
# Forward relationship # Forward relationship
return self.to_native(pk) return self.to_native(pk)

View File

@ -293,6 +293,7 @@ class BaseSerializer(Field):
Override default so that we can apply ModelSerializer as a nested Override default so that we can apply ModelSerializer as a nested
field to relationships. field to relationships.
""" """
try:
if self.source: if self.source:
for component in self.source.split('.'): for component in self.source.split('.'):
obj = getattr(obj, component) obj = getattr(obj, component)
@ -301,7 +302,9 @@ class BaseSerializer(Field):
else: else:
obj = getattr(obj, field_name) obj = getattr(obj, field_name)
if is_simple_callable(obj): if is_simple_callable(obj):
obj = value() obj = obj()
except ObjectDoesNotExist:
return None
# If the object has an "all" method, assume it's a relationship # If the object has an "all" method, assume it's a relationship
if is_simple_callable(getattr(obj, 'all', None)): if is_simple_callable(getattr(obj, 'all', None)):

View File

@ -205,3 +205,8 @@ class NullableForeignKeySource(RESTFrameworkModel):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True, target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True,
related_name='nullable_sources') related_name='nullable_sources')
class NullableOneToOneSource(RESTFrameworkModel):
name = models.CharField(max_length=100)
target = models.OneToOneField(ForeignKeyTarget, null=True, blank=True,
related_name='nullable_source')

View File

@ -1,7 +1,7 @@
from django.db import models from django.db import models
from django.test import TestCase from django.test import TestCase
from rest_framework import serializers from rest_framework import serializers
from rest_framework.tests.models import ForeignKeyTarget, ForeignKeySource, NullableForeignKeySource from rest_framework.tests.models import ForeignKeyTarget, ForeignKeySource, NullableForeignKeySource, NullableOneToOneSource
class ForeignKeySourceSerializer(serializers.ModelSerializer): class ForeignKeySourceSerializer(serializers.ModelSerializer):
@ -28,6 +28,13 @@ class NullableForeignKeySourceSerializer(serializers.ModelSerializer):
model = NullableForeignKeySource model = NullableForeignKeySource
class NullableForeignKeyTargetSerializer(serializers.ModelSerializer):
nullable_source = serializers.PrimaryKeyRelatedField()
class Meta:
model = ForeignKeyTarget
class ReverseForeignKeyTests(TestCase): class ReverseForeignKeyTests(TestCase):
def setUp(self): def setUp(self):
target = ForeignKeyTarget(name='target-1') target = ForeignKeyTarget(name='target-1')
@ -67,6 +74,10 @@ class NestedNullableForeignKeyTests(TestCase):
def setUp(self): def setUp(self):
target = ForeignKeyTarget(name='target-1') target = ForeignKeyTarget(name='target-1')
target.save() target.save()
new_target = ForeignKeyTarget(name='target-2')
new_target.save()
one_source = NullableOneToOneSource(name='one-source-1', target=target)
one_source.save()
for idx in range(1, 4): for idx in range(1, 4):
if idx == 3: if idx == 3:
target = None target = None
@ -82,3 +93,12 @@ class NestedNullableForeignKeyTests(TestCase):
{'id': 3, 'name': u'source-3', 'target': None}, {'id': 3, 'name': u'source-3', 'target': None},
] ]
self.assertEquals(serializer.data, expected) self.assertEquals(serializer.data, expected)
def test_reverse_foreign_key_retrieve_with_null(self):
queryset = ForeignKeyTarget.objects.all()
serializer = NullableForeignKeyTargetSerializer(queryset)
expected = [
{'id': 1, 'name': u'target-1', 'nullable_source': 1},
{'id': 2, 'name': u'target-2', 'nullable_source': None},
]
self.assertEquals(serializer.data, expected)