Django Rest API:如何在序列化模型时摆脱 json 中的 'UUID'?
Django Rest API: How to get rid of 'UUID' in json when serializing models?
为什么 'UUID' 出现在 'profile' 键的值前面,如何正确删除它?
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
输出:
{'id': '92ca258e-8624-434a-b61d-e1cd3b80e0e8', 'profile': UUID('0081b028-0a11-47fb-971e-c47177ed93be')
你可以试试,serializers.CharField
class ShiftSerializer(serializers.ModelSerializer):
profile = serializers.CharField(read_only=True)
UUID 将在 JSONRenderer 渲染时得到更正。
你可以重写 representation
,像这样
class ShiftSerializer(serializers.ModelSerializer):
class Meta:
model = Shift
fields = '__all__'
def to_representation(self, obj):
return {
"id": obj.id,
"profile": obj.profile.id,
"location": obj.location,
"date": obj.date,
"start_time": obj.start_time,
}
tl;dr
请参阅底部的解决方案。
问题
序列化器上的属性 .data
应该 return 序列化器和所有字段上对象 (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) 的唯一原始表示。
@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
来源:https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py#L505-L529
以 uuid.UUID
作为主键的模型存在问题。 PrimaryKeyRelatedField
returns uuid.UUID
实例 - 这显然不是导致例如UUID('')
不是 JSON 可序列化错误。
当PrimaryKeyRelatedField
上的pk_field
属性没有设置时,to_representation
方法只是returns uuid.UUID
实例,见相关代码:
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
来源:https://github.com/encode/django-rest-framework/blob/master/rest_framework/relations.py#L269-L272
为什么会出问题
如其他答案和评论所述,JSONRenderer
将正确处理此问题 (http://www.django-rest-framework.org/api-guide/serializers/#serializing-objects)
from rest_framework.renderers import JSONRenderer
json_data = JSONRenderer().render(serializer.data)
但是有些情况下你不想使用JSONRenderer
:
- 您在单元测试期间比较
.data
;
- 您需要将
.data
存储在数据库、文件、...
- 您想通过
requests
post .data
到某些 API: requests.post(..., json=serializer.data)
- ...
解决方法
将 PrimaryKeyRelatedField
上的 pk_field
属性设置为 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'))
并且 uuid.UUID
个实例在访问 serializer.data
时将被正确序列化为 str
。
为什么 'UUID' 出现在 'profile' 键的值前面,如何正确删除它?
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
输出:
{'id': '92ca258e-8624-434a-b61d-e1cd3b80e0e8', 'profile': UUID('0081b028-0a11-47fb-971e-c47177ed93be')
你可以试试,serializers.CharField
class ShiftSerializer(serializers.ModelSerializer):
profile = serializers.CharField(read_only=True)
UUID 将在 JSONRenderer 渲染时得到更正。
你可以重写 representation
,像这样
class ShiftSerializer(serializers.ModelSerializer):
class Meta:
model = Shift
fields = '__all__'
def to_representation(self, obj):
return {
"id": obj.id,
"profile": obj.profile.id,
"location": obj.location,
"date": obj.date,
"start_time": obj.start_time,
}
tl;dr
请参阅底部的解决方案。
问题
序列化器上的属性 .data
应该 return 序列化器和所有字段上对象 (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) 的唯一原始表示。
@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
来源:https://github.com/encode/django-rest-framework/blob/master/rest_framework/serializers.py#L505-L529
以 uuid.UUID
作为主键的模型存在问题。 PrimaryKeyRelatedField
returns uuid.UUID
实例 - 这显然不是导致例如UUID('')
不是 JSON 可序列化错误。
当PrimaryKeyRelatedField
上的pk_field
属性没有设置时,to_representation
方法只是returns uuid.UUID
实例,见相关代码:
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
来源:https://github.com/encode/django-rest-framework/blob/master/rest_framework/relations.py#L269-L272
为什么会出问题
如其他答案和评论所述,JSONRenderer
将正确处理此问题 (http://www.django-rest-framework.org/api-guide/serializers/#serializing-objects)
from rest_framework.renderers import JSONRenderer
json_data = JSONRenderer().render(serializer.data)
但是有些情况下你不想使用JSONRenderer
:
- 您在单元测试期间比较
.data
; - 您需要将
.data
存储在数据库、文件、... - 您想通过
requests
post.data
到某些 API:requests.post(..., json=serializer.data)
- ...
解决方法
将 PrimaryKeyRelatedField
上的 pk_field
属性设置为 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'))
并且 uuid.UUID
个实例在访问 serializer.data
时将被正确序列化为 str
。