mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-01-23 15:54:16 +03:00
Handle ObjectDoesNotExist exceptions when serializing null reverse one-to-one
This commit is contained in:
parent
ad671022e1
commit
213981cef3
|
@ -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):
|
||||||
value = getattr(obj, self.source or field_name)
|
try:
|
||||||
|
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)
|
||||||
obj = getattr(obj, self.source or field_name)
|
try:
|
||||||
|
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)
|
||||||
|
|
|
@ -293,15 +293,18 @@ 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.
|
||||||
"""
|
"""
|
||||||
if self.source:
|
try:
|
||||||
for component in self.source.split('.'):
|
if self.source:
|
||||||
obj = getattr(obj, component)
|
for component in self.source.split('.'):
|
||||||
|
obj = getattr(obj, component)
|
||||||
|
if is_simple_callable(obj):
|
||||||
|
obj = obj()
|
||||||
|
else:
|
||||||
|
obj = getattr(obj, field_name)
|
||||||
if is_simple_callable(obj):
|
if is_simple_callable(obj):
|
||||||
obj = obj()
|
obj = obj()
|
||||||
else:
|
except ObjectDoesNotExist:
|
||||||
obj = getattr(obj, field_name)
|
return None
|
||||||
if is_simple_callable(obj):
|
|
||||||
obj = value()
|
|
||||||
|
|
||||||
# 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)):
|
||||||
|
|
|
@ -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')
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user