Skip to content

Commit e8bca56

Browse files
committed
Custom serialization of PrimaryKeyRelatedField values
Adds a 'pk_field' parameter which can be used to proxy serialization and deserialization of arbitrary primary key values.
1 parent cdd3aca commit e8bca56

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

docs/api-guide/relations.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ By default this field is read-write, although you can change this behavior using
116116
* `queryset` - The queryset used for model instance lookups when validating the field input. Relationships must either set a queryset explicitly, or set `read_only=True`.
117117
* `many` - If applied to a to-many relationship, you should set this argument to `True`.
118118
* `allow_null` - If set to `True`, the field will accept values of `None` or the empty string for nullable relationships. Defaults to `False`.
119+
* `pk_field` - Set to a field to control serialization/deserialization of the primary key's value. For example, `pk_field=UUIDField(format='hex')` would serialize a UUID primary key into its compact hex representation.
120+
119121

120122
## HyperlinkedRelatedField
121123

rest_framework/relations.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,10 +134,16 @@ class PrimaryKeyRelatedField(RelatedField):
134134
'incorrect_type': _('Incorrect type. Expected pk value, received {data_type}.'),
135135
}
136136

137+
def __init__(self, **kwargs):
138+
self.pk_field = kwargs.pop('pk_field', None)
139+
super(PrimaryKeyRelatedField, self).__init__(**kwargs)
140+
137141
def use_pk_only_optimization(self):
138142
return True
139143

140144
def to_internal_value(self, data):
145+
if self.pk_field is not None:
146+
data = self.pk_field.to_internal_value(data)
141147
try:
142148
return self.get_queryset().get(pk=data)
143149
except ObjectDoesNotExist:
@@ -146,6 +152,8 @@ def to_internal_value(self, data):
146152
self.fail('incorrect_type', data_type=type(data).__name__)
147153

148154
def to_representation(self, value):
155+
if self.pk_field is not None:
156+
return self.pk_field.to_representation(value.pk)
149157
return value.pk
150158

151159

tests/test_relations.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import uuid
12
from .utils import mock_reverse, fail_reverse, BadType, MockObject, MockQueryset
23
from django.core.exceptions import ImproperlyConfigured
34
from django.utils.datastructures import MultiValueDict
@@ -48,6 +49,34 @@ def test_pk_representation(self):
4849
assert representation == self.instance.pk
4950

5051

52+
class TestProxiedPrimaryKeyRelatedField(APISimpleTestCase):
53+
def setUp(self):
54+
self.queryset = MockQueryset([
55+
MockObject(pk=uuid.UUID(int=0), name='foo'),
56+
MockObject(pk=uuid.UUID(int=1), name='bar'),
57+
MockObject(pk=uuid.UUID(int=2), name='baz')
58+
])
59+
self.instance = self.queryset.items[2]
60+
self.field = serializers.PrimaryKeyRelatedField(
61+
queryset=self.queryset,
62+
pk_field=serializers.UUIDField(format='int')
63+
)
64+
65+
def test_pk_related_lookup_exists(self):
66+
instance = self.field.to_internal_value(self.instance.pk.int)
67+
assert instance is self.instance
68+
69+
def test_pk_related_lookup_does_not_exist(self):
70+
with pytest.raises(serializers.ValidationError) as excinfo:
71+
self.field.to_internal_value(4)
72+
msg = excinfo.value.detail[0]
73+
assert msg == 'Invalid pk "00000000-0000-0000-0000-000000000004" - object does not exist.'
74+
75+
def test_pk_representation(self):
76+
representation = self.field.to_representation(self.instance)
77+
assert representation == self.instance.pk.int
78+
79+
5180
class TestHyperlinkedIdentityField(APISimpleTestCase):
5281
def setUp(self):
5382
self.instance = MockObject(pk=1, name='foo')

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