在Django Rest Framework序列化器的validated_data中无法获取非模型字段

13

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

正确的处理方法似乎是在 Serializer 的 update 方法中处理。我的问题是,这个非模型的 deleted 字段在验证期间被删除了,因此不再可用。将 deleted 添加为 SerializerMethodField 也没有帮助。目前,我从 Serializer 的 initial_data 属性中获取我的 deleted 信息,但这感觉不对。

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

Models:

    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作为序列化程序的基类,则每个子项都将具有一个URL,您可以轻松地进行DELETE操作。 - Ross Rogers
这是一个有趣的探索角度。然而,主要问题在于validated_data中缺少关于需要删除哪些项的信息。 - jjmurre
我的意思是,在客户端,不要在子项上设置标志“delete”,而是对该对象执行HTTP“DELETE”操作并将其从容器中删除。您不应该在Django内部执行“DELETE”(如果我可以猜测您在暗示这种方法)。 - Ross Rogers
啊,我误解了。很好的方法,谢谢! - jjmurre
2个回答

33

你可以通过覆盖to_internal_value函数来添加非模型字段:

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中以任何您想要的方式处理它。


1
如果您正在进行PUT请求,您的视图可能会调用self.perform_update(serializer)。请将其更改为
serializer.save(<my_non_model_field>=request.data.get('<my_non_model_field>', <default_value>)

所有的 kwargs 都会被传递到你的序列化器的 validated_data 中。请确保正确地转换传入的值(例如转换为布尔值、整数等)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接