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