mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-26 19:43:59 +03:00
Custom serialization of PrimaryKeyRelatedField values
Adds a 'pk_field' parameter which can be used to proxy serialization and deserialization of arbitrary primary key values.
This commit is contained in:
parent
b0889446a5
commit
a1e0bae9da
|
@ -116,6 +116,8 @@ By default this field is read-write, although you can change this behavior using
|
||||||
* `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`.
|
* `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`.
|
||||||
* `many` - If applied to a to-many relationship, you should set this argument to `True`.
|
* `many` - If applied to a to-many relationship, you should set this argument to `True`.
|
||||||
* `allow_null` - If set to `True`, the field will accept values of `None` or the empty string for nullable relationships. Defaults to `False`.
|
* `allow_null` - If set to `True`, the field will accept values of `None` or the empty string for nullable relationships. Defaults to `False`.
|
||||||
|
* `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.
|
||||||
|
|
||||||
|
|
||||||
## HyperlinkedRelatedField
|
## HyperlinkedRelatedField
|
||||||
|
|
||||||
|
|
|
@ -134,10 +134,16 @@ class PrimaryKeyRelatedField(RelatedField):
|
||||||
'incorrect_type': _('Incorrect type. Expected pk value, received {data_type}.'),
|
'incorrect_type': _('Incorrect type. Expected pk value, received {data_type}.'),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, **kwargs):
|
||||||
|
self.pk_field = kwargs.pop('pk_field', None)
|
||||||
|
super(PrimaryKeyRelatedField, self).__init__(**kwargs)
|
||||||
|
|
||||||
def use_pk_only_optimization(self):
|
def use_pk_only_optimization(self):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def to_internal_value(self, data):
|
def to_internal_value(self, data):
|
||||||
|
if self.pk_field is not None:
|
||||||
|
data = self.pk_field.to_internal_value(data)
|
||||||
try:
|
try:
|
||||||
return self.get_queryset().get(pk=data)
|
return self.get_queryset().get(pk=data)
|
||||||
except ObjectDoesNotExist:
|
except ObjectDoesNotExist:
|
||||||
|
@ -146,6 +152,8 @@ class PrimaryKeyRelatedField(RelatedField):
|
||||||
self.fail('incorrect_type', data_type=type(data).__name__)
|
self.fail('incorrect_type', data_type=type(data).__name__)
|
||||||
|
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
|
if self.pk_field is not None:
|
||||||
|
return self.pk_field.to_representation(value.pk)
|
||||||
return value.pk
|
return value.pk
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import uuid
|
||||||
from .utils import mock_reverse, fail_reverse, BadType, MockObject, MockQueryset
|
from .utils import mock_reverse, fail_reverse, BadType, MockObject, MockQueryset
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
from django.utils.datastructures import MultiValueDict
|
from django.utils.datastructures import MultiValueDict
|
||||||
|
@ -48,6 +49,34 @@ class TestPrimaryKeyRelatedField(APISimpleTestCase):
|
||||||
assert representation == self.instance.pk
|
assert representation == self.instance.pk
|
||||||
|
|
||||||
|
|
||||||
|
class TestProxiedPrimaryKeyRelatedField(APISimpleTestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.queryset = MockQueryset([
|
||||||
|
MockObject(pk=uuid.UUID(int=0), name='foo'),
|
||||||
|
MockObject(pk=uuid.UUID(int=1), name='bar'),
|
||||||
|
MockObject(pk=uuid.UUID(int=2), name='baz')
|
||||||
|
])
|
||||||
|
self.instance = self.queryset.items[2]
|
||||||
|
self.field = serializers.PrimaryKeyRelatedField(
|
||||||
|
queryset=self.queryset,
|
||||||
|
pk_field=serializers.UUIDField(format='int')
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_pk_related_lookup_exists(self):
|
||||||
|
instance = self.field.to_internal_value(self.instance.pk.int)
|
||||||
|
assert instance is self.instance
|
||||||
|
|
||||||
|
def test_pk_related_lookup_does_not_exist(self):
|
||||||
|
with pytest.raises(serializers.ValidationError) as excinfo:
|
||||||
|
self.field.to_internal_value(4)
|
||||||
|
msg = excinfo.value.detail[0]
|
||||||
|
assert msg == 'Invalid pk "00000000-0000-0000-0000-000000000004" - object does not exist.'
|
||||||
|
|
||||||
|
def test_pk_representation(self):
|
||||||
|
representation = self.field.to_representation(self.instance)
|
||||||
|
assert representation == self.instance.pk.int
|
||||||
|
|
||||||
|
|
||||||
class TestHyperlinkedIdentityField(APISimpleTestCase):
|
class TestHyperlinkedIdentityField(APISimpleTestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.instance = MockObject(pk=1, name='foo')
|
self.instance = MockObject(pk=1, name='foo')
|
||||||
|
|
Loading…
Reference in New Issue
Block a user