如何使用不同的Serializer反序列化POST请求

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用不同的Serializer反序列化POST请求相关的知识,希望对你有一定的参考价值。

我正在尝试使用与从Model派生的序列化程序不同的序列化程序在我的API端点中处理POST请求,并用于GET或PUT请求。 POSTed消息的格式与Model和GET / PUT的格式不同,必须在存储到数据库之前进行预处理。

作为我的问题的演示,我做了一个非常简单的模型和相应的API视图和序列化器:

class Message(models.Model): 
    message = models.CharField(max_length = 500)

class MessageSerializer(serializers.ModelSerializer):
    class Meta:
        model = Message
        fields = ('message',)

class MessageViewSet(viewsets.ModelViewSet):
    queryset = Message.objects.all().order_by('-pk')
    serializer_class = MessageSerializer

这很好用。然后我尝试覆盖MessageViewSet.create()以不同方式处理POST请求。

class MessageSerializer_FromTo(serializers.Serializer):
    sender = serializers.EmailField()
    recipient = serializers.EmailField()

    def create(self, validated_data):
        message = "Message from <{sender}> to <{recipient}>".format(**validated_data)
        return Message(message)

class MessageViewSet(viewsets.ModelViewSet):
    queryset = Message.objects.all().order_by('-pk')
    serializer_class = MessageSerializer

    # Handle POST requests differently
    def create(self, request, format=None):
        message = MessageSerializer_FromTo(data = request.data)
        if message.is_valid():
            message.save()
            return Response(message.data, status=status.HTTP_201_CREATED)
        return Response(message.errors, status=status.HTTP_400_BAD_REQUEST)

基本上我想把这个JSON传递给POST / api / messages /

{"sender": "some@one.com", "recipient": "someone@else.org"}

GET / api / messages / 1 /应该返回

{"message": "Message from <some@one.com> to <someone@else.org>"}

但是,POST失败并显示以下消息:

Internal Server Error: /api/messages/
Traceback (most recent call last):
  File ".../rest_framework/fields.py", line 441, in get_attribute
    return get_attribute(instance, self.source_attrs)
  File ".../rest_framework/fields.py", line 100, in get_attribute
    instance = getattr(instance, attr)
AttributeError: 'Message' object has no attribute 'sender'


During handling of the above exception, another exception occurred:
[...]
AttributeError: Got AttributeError when attempting to get a value for field `sender` on serializer `MessageSerializer_FromTo`.
The serializer field might be named incorrectly and not match any attribute or key on the `Message` instance.
Original exception text was: 'Message' object has no attribute 'sender'.
[26/Feb/2018 05:09:08] "POST /api/messages/ HTTP/1.1" 500 19059

这只是为了显示问题,我在POST处理程序中做了更复杂的事情,但错误是这样的。

知道如何实现我的需求吗?即接受与模型字段完全不同的POST字段?

谢谢!

更新:完整的代码在这里:https://github.com/mludvig/drf-demo

答案

问题出在您的序列化程序中。您只是将模型类Message(message)作为create function的输出而不是Message对象传递

class MessageSerializer_FromTo(serializers.Serializer):
    sender = serializers.EmailField(write_only=True)
    recipient = serializers.EmailField(write_only=True)
    message = serializers.CharField(read_only=True, max_length = 500)   

    def create(self, validated_data):
        message = "Message from <{sender}> to <{recipient}>".format(**validated_data)
        return Message.objects.create(message=message)
另一答案

您可以通过覆盖视图集的get_serializer_class方法,根据方法类型获取不同的序列化程序

class MessageViewSet(viewsets.ModelViewSet):
    model = Message

    def get_serializer_class(self):
        serializers_class_map = {
            'default': DefaultSerializer,
            'create': CreateMessageSerializer,
        }
        return serializers_class_map.get(self.action, serializers_class_map['default'])

您也可以覆盖to_representationCreateMessageSerializer方法以获得不同的输出

class CreateMessageSerializer(serializer.ModelSerializer):

    class Meta:
        model = Message
        fields = (
            'sender', 'recipient'
        )

    def to_representation(self, instance):
        return {
            'message': "Message from <{0.sender}> to <{0.recipient}>".format(instance)
        }
另一答案

要使用不同的序列化程序,具体取决于序列化程序是否将请求中的数据反序列化或序列化响应,您可以使用drf-rw-serializers

它有一些通用类来帮助你构建像Django REST Framework那样的视图,但是,它们不使用一个serializer_class,而是使用read_serializer_classwrite_serializer_class

您可以在documentation中阅读有关安装和使用的更多说明。

以上是关于如何使用不同的Serializer反序列化POST请求的主要内容,如果未能解决你的问题,请参考以下文章

如何使 Symfony Serializer 的属性可以为空

第三章drf框架 - 序列化组件 | Serializer

在JMS Serializer上反序列化期间构造对象

Serializer组件

序列化组件serializer之序列化与反序列化

drf序列化组件