mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-30 23:47:53 +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