Skip to content

Commit 0e83063

Browse files
committed
Merge pull request #3936 from carltongibson/null-uuid-fk-take2
Fix None UUID ForeignKey serialization
2 parents 85e57af + 2ef74cf commit 0e83063

File tree

4 files changed

+48
-4
lines changed

4 files changed

+48
-4
lines changed

docs/topics/release-notes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ You can determine your currently installed version using `pip freeze`:
4545
**Unreleased**
4646

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

4950
### 3.3.2
5051

rest_framework/serializers.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -464,9 +464,13 @@ def to_representation(self, instance):
464464
except SkipField:
465465
continue
466466

467-
if attribute is None:
468-
# We skip `to_representation` for `None` values so that
469-
# fields do not have to explicitly deal with that case.
467+
# We skip `to_representation` for `None` values so that fields do
468+
# not have to explicitly deal with that case.
469+
#
470+
# For related fields with `use_pk_only_optimization` we need to
471+
# resolve the pk value.
472+
check_for_none = attribute.pk if isinstance(attribute, PKOnlyObject) else attribute
473+
if check_for_none is None:
470474
ret[field.field_name] = None
471475
else:
472476
ret[field.field_name] = field.to_representation(attribute)

tests/models.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
from __future__ import unicode_literals
22

3+
import uuid
4+
35
from django.db import models
46
from django.utils.translation import ugettext_lazy as _
57

@@ -46,6 +48,11 @@ class ForeignKeyTarget(RESTFrameworkModel):
4648
name = models.CharField(max_length=100)
4749

4850

51+
class UUIDForeignKeyTarget(RESTFrameworkModel):
52+
uuid = models.UUIDField(primary_key=True, default=uuid.uuid4)
53+
name = models.CharField(max_length=100)
54+
55+
4956
class ForeignKeySource(RESTFrameworkModel):
5057
name = models.CharField(max_length=100)
5158
target = models.ForeignKey(ForeignKeyTarget, related_name='sources',
@@ -62,6 +69,14 @@ class NullableForeignKeySource(RESTFrameworkModel):
6269
on_delete=models.CASCADE)
6370

6471

72+
class NullableUUIDForeignKeySource(RESTFrameworkModel):
73+
name = models.CharField(max_length=100)
74+
target = models.ForeignKey(ForeignKeyTarget, null=True, blank=True,
75+
related_name='nullable_sources',
76+
verbose_name='Optional target object',
77+
on_delete=models.CASCADE)
78+
79+
6580
# OneToOne
6681
class OneToOneTarget(RESTFrameworkModel):
6782
name = models.CharField(max_length=100)

tests/test_relations_pk.py

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
from rest_framework import serializers
77
from tests.models import (
88
ForeignKeySource, ForeignKeyTarget, ManyToManySource, ManyToManyTarget,
9-
NullableForeignKeySource, NullableOneToOneSource, OneToOneTarget
9+
NullableForeignKeySource, NullableOneToOneSource,
10+
NullableUUIDForeignKeySource, OneToOneTarget, UUIDForeignKeyTarget
1011
)
1112

1213

@@ -43,6 +44,18 @@ class Meta:
4344
fields = ('id', 'name', 'target')
4445

4546

47+
# Nullable UUIDForeignKey
48+
class NullableUUIDForeignKeySourceSerializer(serializers.ModelSerializer):
49+
target = serializers.PrimaryKeyRelatedField(
50+
pk_field=serializers.UUIDField(),
51+
queryset=UUIDForeignKeyTarget.objects.all(),
52+
allow_null=True)
53+
54+
class Meta:
55+
model = NullableUUIDForeignKeySource
56+
fields = ('id', 'name', 'target')
57+
58+
4659
# Nullable OneToOne
4760
class NullableOneToOneTargetSerializer(serializers.ModelSerializer):
4861
class Meta:
@@ -432,6 +445,17 @@ def test_foreign_key_update_with_valid_emptystring(self):
432445
]
433446
self.assertEqual(serializer.data, expected)
434447

448+
def test_null_uuid_foreign_key_serializes_as_none(self):
449+
source = NullableUUIDForeignKeySource(name='Source')
450+
serializer = NullableUUIDForeignKeySourceSerializer(source)
451+
data = serializer.data
452+
self.assertEqual(data["target"], None)
453+
454+
def test_nullable_uuid_foreign_key_is_valid_when_none(self):
455+
data = {"name": "Source", "target": None}
456+
serializer = NullableUUIDForeignKeySourceSerializer(data=data)
457+
self.assertTrue(serializer.is_valid(), serializer.errors)
458+
435459

436460
class PKNullableOneToOneTests(TestCase):
437461
def setUp(self):

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy