mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-26 05:31:07 +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