【问题标题】:Django Rest API: How to get rid of 'UUID' in json when serializing models?Django Rest API:序列化模型时如何摆脱 json 中的“UUID”?
【发布时间】:2018-02-17 02:19:36
【问题描述】:

为什么 'UUID' 出现在 'profile' 键的值前面,如何正确删除?

名册/序列化器.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)

名册/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')

【问题讨论】:

  • 为什么要删除它?它将被 json 渲染器正确渲染。
  • 你说的完全正确!谢谢!
  • 你的问题很有道理@meowmeow。因为我们对序列化器输出的期望是本机类型。 UUID 不是本机类型。当我使用 DRF:self.assertDictEqual(posted_data, produced_data) 编写测试检查我在端点上发布的内容是否产生正确的 json 时,这也会给我带来一个问题。因为它会将字符串中的 UUID 与 UUID() 对象进行比较。

标签: django django-rest-framework django-serializer


【解决方案1】:

tl;dr

请参阅底部的解决方案

问题

序列化器上的属性.data 应该只返回对象的原始表示(http://www.django-rest-framework.org/api-guide/serializers/#baseserializer)。这应该通过在序列化程序和所有字段上调用 ​​to_representation() 方法 (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 返回 uuid.UUID 实例 - 这显然不是导致例如UUID('') 不是 JSON 可序列化错误。

PrimaryKeyRelatedField上的pk_field属性未设置时,to_representation方法只返回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

为什么会出现问题

如其他答案和 cmets 所述,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.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

【讨论】:

  • 有效!但就我而言,我必须使用 id = serializers.UUIDField(format='hex') 来排除 UUID 连字符。
【解决方案2】:

你可以重写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,
        }

【讨论】:

    【解决方案3】:

    UUID 会在 JSONRenderer 渲染时被修正。

    【讨论】:

      【解决方案4】:

      你可以尝试使用,serializers.CharField

      class ShiftSerializer(serializers.ModelSerializer):
           profile = serializers.CharField(read_only=True)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-07-20
        • 2017-01-20
        • 1970-01-01
        • 1970-01-01
        • 2011-05-11
        • 2019-03-01
        • 2014-06-03
        • 1970-01-01
        相关资源
        最近更新 更多