Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix None UUID ForeignKey serialization #3936

Merged
merged 3 commits into from
Mar 22, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/topics/release-notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ You can determine your currently installed version using `pip freeze`:
**Unreleased**

* Dropped support for EOL Django 1.7 ([#3933][gh3933])
* Fixed null foreign keys targeting UUIDField primary keys. ([#3936][gh3936])

### 3.3.2

Expand Down
10 changes: 7 additions & 3 deletions rest_framework/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -464,9 +464,13 @@ def to_representation(self, instance):
except SkipField:
continue

if attribute is None:
# We skip `to_representation` for `None` values so that
# fields do not have to explicitly deal with that case.
# We skip `to_representation` for `None` values so that 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
else:
ret[field.field_name] = field.to_representation(attribute)
Expand Down
15 changes: 15 additions & 0 deletions tests/models.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from __future__ import unicode_literals

import uuid

from django.db import models
from django.utils.translation import ugettext_lazy as _

Expand Down Expand Up @@ -46,6 +48,11 @@ class ForeignKeyTarget(RESTFrameworkModel):
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):
name = models.CharField(max_length=100)
target = models.ForeignKey(ForeignKeyTarget, related_name='sources',
Expand All @@ -62,6 +69,14 @@ class NullableForeignKeySource(RESTFrameworkModel):
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
class OneToOneTarget(RESTFrameworkModel):
name = models.CharField(max_length=100)
Expand Down
26 changes: 25 additions & 1 deletion tests/test_relations_pk.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
from rest_framework import serializers
from tests.models import (
ForeignKeySource, ForeignKeyTarget, ManyToManySource, ManyToManyTarget,
NullableForeignKeySource, NullableOneToOneSource, OneToOneTarget
NullableForeignKeySource, NullableOneToOneSource,
NullableUUIDForeignKeySource, OneToOneTarget, UUIDForeignKeyTarget
)


Expand Down Expand Up @@ -43,6 +44,18 @@ class Meta:
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
class NullableOneToOneTargetSerializer(serializers.ModelSerializer):
class Meta:
Expand Down Expand Up @@ -432,6 +445,17 @@ def test_foreign_key_update_with_valid_emptystring(self):
]
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):
def setUp(self):
Expand Down