mirror of
https://github.com/encode/django-rest-framework.git
synced 2024-11-22 17:47:04 +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`.
|
||||
* `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`.
|
||||
* `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
|
||||
|
||||
|
|
|
@ -134,10 +134,16 @@ class PrimaryKeyRelatedField(RelatedField):
|
|||
'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):
|
||||
return True
|
||||
|
||||
def to_internal_value(self, data):
|
||||
if self.pk_field is not None:
|
||||
data = self.pk_field.to_internal_value(data)
|
||||
try:
|
||||
return self.get_queryset().get(pk=data)
|
||||
except ObjectDoesNotExist:
|
||||
|
@ -146,6 +152,8 @@ class PrimaryKeyRelatedField(RelatedField):
|
|||
self.fail('incorrect_type', data_type=type(data).__name__)
|
||||
|
||||
def to_representation(self, value):
|
||||
if self.pk_field is not None:
|
||||
return self.pk_field.to_representation(value.pk)
|
||||
return value.pk
|
||||
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import uuid
|
||||
from .utils import mock_reverse, fail_reverse, BadType, MockObject, MockQueryset
|
||||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
|
@ -48,6 +49,34 @@ class TestPrimaryKeyRelatedField(APISimpleTestCase):
|
|||
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):
|
||||
def setUp(self):
|
||||
self.instance = MockObject(pk=1, name='foo')
|
||||
|
|
Loading…
Reference in New Issue
Block a user