无法在 Django Rest Framework 序列化程序的验证数据中获取非模型字段

Posted

技术标签:

【中文标题】无法在 Django Rest Framework 序列化程序的验证数据中获取非模型字段【英文标题】:Unable to get a non-model field in the validated_data of a Django Rest Framework serializer 【发布时间】:2015-08-20 07:50:30 【问题描述】:

我的 Django 模型中有一个 ItemCollection 和 Items,我希望能够通过 UI 从集合中删除 Items。在 REST PUT 请求中,我为每个项目添加了一个额外的布尔字段 deleted,以表明应该删除一个项目。

处理这个问题的正确方法似乎是在序列化器的update 方法中。 我的问题是这个非模型deleted 字段在验证过程中被删除,所以它不再可用。将deleted 添加为SerializerMethodField 没有帮助。现在我从 Serializer 的 initial_data 属性中获取了我的 deleted 信息,但感觉不对。

我当前的示例代码如下。有人知道更好的方法吗?

型号:

    class ItemCollection(models.Model):
        description = models.CharField(max_length=256)


    class Item(models.Model):
        collection = models.ForeignKey(ItemCollection, related_name="items")

序列化器:

    from django.shortcuts import get_object_or_404
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework import serializers
    from models import Item, ItemCollection


    class ItemSerializer(serializers.ModelSerializer):

        class Meta:
            model = Item


    class ItemCollectionSerializer(serializers.ModelSerializer):

        items = ItemSerializer(many=True, read_only=False)

        class Meta:
            model = ItemCollection

        def update(self, instance, validated_data):
            instance.description = validated_data['description']
            for item, item_obj in zip(
                   self.initial_data['items'], validated_data['items']):
                if item['delete']:
                    instance.items.filter(id=item['id']).delete()
            return instance


    class ItemCollectionView(APIView):

        def get(self, request, ic_id):
            item_collection = get_object_or_404(ItemCollection, pk=ic_id)
            serialized = ItemCollectionSerializer(item_collection).data
            return Response(serialized)

        def put(self, request, ic_id):
            item_collection = get_object_or_404(ItemCollection, pk=ic_id)
            serializer = ItemCollectionSerializer(
               item_collection, data=request.data)
            if serializer.is_valid(raise_exception=True):
                serializer.save()
            return Response(serializer.data)

以及 PUT 请求中的 json 示例:

    
        "id": 2,
        "items": [
            
                "id": 3,
                "collection": 2,
                "delete": true
            
        ],
        "description": "mycoll"
    

【问题讨论】:

为每个需要删除的嵌套模块执行单独的 HTTP DELETE 是否可以接受?如果您使用serializers.HyperlinkedModelSerializer 作为序列化程序的基类,每个子项都会有一个您可以轻松使用DELETE 的URL。 这是一个有趣的探索角度。虽然,主要问题是 validated_data 中缺少有关需要删除哪些项目的信息。 我的意思是,在客户端,不要在子项上设置标志delete,只需对该对象执行 HTTP DELETE 并将其从容器中删除。您不会在 Django 内部执行DELETE(如果我可以假设您是在暗示这种方法。) 啊,我误会了。不错的方法,tx! 【参考方案1】:

您可以通过覆盖to_internal_value fn 来添加非模型字段:

def to_internal_value(self, data):
    internal_value = super(MySerializer, self).to_internal_value(data)
    my_non_model_field_raw_value = data.get("my_non_model_field")
    my_non_model_field_value = ConvertRawValueInSomeCleverWay(my_non_model_field_raw_value)
    internal_value.update(
        "my_non_model_field": my_non_model_field_value
    )
    return internal_value

然后您可以在createupdate 中随意处理它。

【讨论】:

【参考方案2】:

如果您正在执行 PUT 请求,您的视图可能正在调用 self.perform_update(serializer)。换成

serializer.save(<my_non_model_field>=request.data.get('<my_non_model_field>', <default_value>)

所有kwargs 都被传递到验证数据到您的序列化程序。 确保正确转换传入值(布尔值、整数等)

【讨论】:

以上是关于无法在 Django Rest Framework 序列化程序的验证数据中获取非模型字段的主要内容,如果未能解决你的问题,请参考以下文章

无法让 CORS 与内容类型一起使用 - Django Rest Framework

我无法使用 Django-Rest-Framework 注册用户

Django Rest Framework:无法序列化或保存上传的图像

无法在 Django Rest Framework 序列化程序的验证数据中获取非模型字段

Django Rest Framework 抱怨 CSRF

使用 RSA 算法 Django Rest Framework 简单 JWT 时出现错误无法反序列化密钥数据