Merge pull request #3936 from carltongibson/null-uuid-fk-take2

Fix None UUID ForeignKey serialization
This commit is contained in:
Xavier Ordoquy 2016-03-22 22:46:33 +01:00
commit 0e8306341d
4 changed files with 48 additions and 4 deletions

View File

@ -45,6 +45,7 @@ You can determine your currently installed version using `pip freeze`:
**Unreleased** **Unreleased**
* Dropped support for EOL Django 1.7 ([#3933][gh3933]) * Dropped support for EOL Django 1.7 ([#3933][gh3933])
* Fixed null foreign keys targeting UUIDField primary keys. ([#3936][gh3936])
### 3.3.2 ### 3.3.2

View File

@ -464,9 +464,13 @@ class Serializer(BaseSerializer):
except SkipField: except SkipField:
continue continue
if attribute is None: # We skip `to_representation` for `None` values so that fields do
# We skip `to_representation` for `None` values so that # not have to explicitly deal with that case.
# fields do not have to explicitly deal with that case. #
# For related fields with `use_pk_only_optimization` we need to
# resolve the pk value.
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
if check_for_none is None:
ret[field.field_name] = None ret[field.field_name] = None
else: else:
ret[field.field_name] = field.to_representation(attribute) ret[field.field_name] = field.to_representation(attribute)

View File

@ -1,5 +1,7 @@
from __future__ import unicode_literals from __future__ import unicode_literals
import uuid
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -46,6 +48,11 @@ class ForeignKeyTarget(RESTFrameworkModel):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
class UUIDForeignKeyTarget(RESTFrameworkModel):
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
name = models.CharField(max_length=100)
class ForeignKeySource(RESTFrameworkModel): class ForeignKeySource(RESTFrameworkModel):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)
target = models.ForeignKey(ForeignKeyTarget, related_name='sources', target = models.ForeignKey(ForeignKeyTarget, related_name='sources',
@ -62,6 +69,14 @@ class NullableForeignKeySource(RESTFrameworkModel):
on_delete=models.CASCADE) on_delete=models.CASCADE)
class NullableUUIDForeignKeySource(RESTFrameworkModel):
name = models.CharField(max_length=100)
target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True,
related_name='nullable_sources',
verbose_name='Optional target object',
on_delete=models.CASCADE)
# OneToOne # OneToOne
class OneToOneTarget(RESTFrameworkModel): class OneToOneTarget(RESTFrameworkModel):
name = models.CharField(max_length=100) name = models.CharField(max_length=100)

View File

@ -6,7 +6,8 @@ from django.utils import six
from rest_framework import serializers from rest_framework import serializers
from tests.models import ( from tests.models import (
ForeignKeySource, ForeignKeyTarget, ManyToManySource, ManyToManyTarget, ForeignKeySource, ForeignKeyTarget, ManyToManySource, ManyToManyTarget,
NullableForeignKeySource, NullableOneToOneSource, OneToOneTarget NullableForeignKeySource, NullableOneToOneSource,
NullableUUIDForeignKeySource, OneToOneTarget, UUIDForeignKeyTarget
) )
@ -43,6 +44,18 @@ class NullableForeignKeySourceSerializer(serializers.ModelSerializer):
fields = ('id', 'name', 'target') fields = ('id', 'name', 'target')
# Nullable UUIDForeignKey
class NullableUUIDForeignKeySourceSerializer(serializers.ModelSerializer):
target = serializers.PrimaryKeyRelatedField(
pk_field=serializers.UUIDField(),
queryset=UUIDForeignKeyTarget.objects.all(),
allow_null=True)
class Meta:
model = NullableUUIDForeignKeySource
fields = ('id', 'name', 'target')
# Nullable OneToOne # Nullable OneToOne
class NullableOneToOneTargetSerializer(serializers.ModelSerializer): class NullableOneToOneTargetSerializer(serializers.ModelSerializer):
class Meta: class Meta:
@ -432,6 +445,17 @@ class PKNullableForeignKeyTests(TestCase):
] ]
self.assertEqual(serializer.data, expected) self.assertEqual(serializer.data, expected)
def test_null_uuid_foreign_key_serializes_as_none(self):
source = NullableUUIDForeignKeySource(name='Source')
serializer = NullableUUIDForeignKeySourceSerializer(source)
data = serializer.data
self.assertEqual(data["target"], None)
def test_nullable_uuid_foreign_key_is_valid_when_none(self):
data = {"name": "Source", "target": None}
serializer = NullableUUIDForeignKeySourceSerializer(data=data)
self.assertTrue(serializer.is_valid(), serializer.errors)
class PKNullableOneToOneTests(TestCase): class PKNullableOneToOneTests(TestCase):
def setUp(self): def setUp(self):