Why does 'UUID' appear in front of the value of 'profile' key and how do I remove it properly?
roster/serializers.py
class ShiftSerializer(serializers.ModelSerializer):
class Meta:
model = Shift
fields = ('id', 'profile', 'location', 'date', 'start_time', 'end_time')
profile/models.py
class Profile(models.Models):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
roster/models.py
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=True)
profile = models.ForeignKey('profiles.Profile', null=True, blank=True)
python manage.py shell
from roster.models import Shift
from roster.serializers import ShiftSerializer
myshift = Shift.objects.first()
serializer = ShiftSerializer(myshift)
serializer.data
Output:
{'id': '92ca258e-8624-434a-b61d-e1cd3b80e0e8', 'profile': UUID('0081b028-0a11-47fb-971e-c47177ed93be')
Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
HyperlinkedModelSerializer is a layer of abstraction over the default serializer that allows to quickly create a serializer for a model in Django. Django REST Framework is a wrapper over default Django Framework, basically used to create APIs of various kinds.
UUID, Universal Unique Identifier, is a python library that helps in generating random objects of 128 bits as ids. It provides the uniqueness as it generates ids on the basis of time, Computer hardware (MAC etc.). Universally unique identifiers are a good alternative to AutoField for primary_key .
Django Rest Framework makes it easy to use your Django Server as an REST API. REST stands for "representational state transfer" and API stands for application programming interface. You can build a restful api using regular Django, but it will be very tidious. DRF makes everything easy.
tl;dr
See The solution at the bottom.
The problem
Attribute .data
on Serializer should return only primitive representation of object (http://www.django-rest-framework.org/api-guide/serializers/#baseserializer). This should be done by calling to_representation()
method (http://www.django-rest-framework.org/api-guide/serializers/#to_representationself-obj) on a serializer and all fields.
@six.add_metaclass(SerializerMetaclass)
class Serializer(BaseSerializer):
# ...
# ...
def to_representation(self, instance):
"""
Object instance -> Dict of primitive datatypes.
"""
# ...
# ...
for field in fields:
# ...
# ...
if check_for_none is None:
ret[field.field_name] = None
else:
ret[field.field_name] = field.to_representation(attribute)
return ret
Source: https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py#L505-L529
There is a problem with models that have uuid.UUID
as a primary key. PrimaryKeyRelatedField
returns uuid.UUID
instance - this is clearly not a primitive type which leads to e.g. UUID('')
is not JSON serializable errors.
When pk_field
attribute on PrimaryKeyRelatedField
is not set, to_representation
method simply returns uuid.UUID
instance, see the related code:
class PrimaryKeyRelatedField(RelatedField):
# ...
def to_representation(self, value):
if self.pk_field is not None:
return self.pk_field.to_representation(value.pk)
return value.pk
Source: https://github.com/encode/django-rest-framework/blob/master/rest_framework/relations.py#L269-L272
Why is it a problem
As stated in other answers and comments, JSONRenderer
will correctly handle this issue (http://www.django-rest-framework.org/api-guide/serializers/#serializing-objects)
from rest_framework.renderers import JSONRenderer
json_data = JSONRenderer().render(serializer.data)
But there are situations when you do not want to use JSONRenderer
:
.data
during unit testing;.data
in database, file, ....data
via requests
to some API: requests.post(..., json=serializer.data)
The solution
Set pk_field
attribute on PrimaryKeyRelatedField
to UUIDField()
:
from rest_framework import serializers
from rest_framework.fields import UUIDField
class ExampleSerializer(serializers.ModelSerializer):
id = serializers.PrimaryKeyRelatedField(required=True,
allow_null=False,
# This will properly serialize uuid.UUID to str:
pk_field=UUIDField(format='hex_verbose'))
And uuid.UUID
instances will be correctly serialized to str
when accessing serializer.data
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With