如何在通用视图中为同一请求使用不同的Django Rest Framework序列化程序

Mar*_*edy 6 django-rest-framework

我在一个API项目中使用Django Rest Framework,并试图弄清楚是否有一种方法可以使用两个不同的序列化程序与通用视图(例如CreateAPIView).我想使用一个序列化程序来反序列化POST请求,而另一个序列化程序用于序列化生成的响应.

这就是我想要做的; 我将使用文档中的Album/Track示例进行说明:

我正在使用的模型具有ForeignKey关系.在API中,我希望能够在分配关系时在请求中包含FK,因此在序列化程序中我使用的是PrimaryKeyRelatedField,类似于AlbumSerializer处理与轨道的关系的方式:

class CreateAlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')
Run Code Online (Sandbox Code Playgroud)

但是,在回复中,我想使用ModelSerializer包含相册的完整表示,而不仅仅是PK,slug等,如下所示:

class AlbumSerializer(serializers.ModelSerializer):
    tracks = TrackSerializer(many=True, read_only=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

class TrackSerializer(serializers.ModelSerializer):
    class Meta:
        model = Album
        fields = ('order', 'title', 'duration')
Run Code Online (Sandbox Code Playgroud)

通用DRF视图允许您指定serializer_class或覆盖get_serializer_class方法,但我无法弄清楚如何使用它来完成我所追求的目标.

有什么明显的东西让我失踪吗?这似乎是一件合理的事情,但我似乎无法理解如何完成它.

mik*_*725 6

方法#1

覆盖DRF中的通用混合ViewSet.例如:

class MyViewSet(CreateModelMixin, MultipleSerializersViewMixin, ViewSet):
    serializer_class = CreateAlbumSerializer

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        saved = self.perform_create(serializer)
        serializer = self.get_serializer(instance=saved, serializer_class=AlbumSerializer)

        headers = self.get_success_headers(serializer.data)
        return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)

    def perform_create(self, serializer):
        return serializer.save()
Run Code Online (Sandbox Code Playgroud)

MultipleSerializersViewMixin取自django-rest-framework-braces.

方法#2

自定义to_representationCreateAlbumSerializer.例如:

class MyViewSet(CreateModelMixin, ViewSet):
    serializer_class = CreateAlbumSerializer

class CreateAlbumSerializer(serializers.ModelSerializer):
    tracks = serializers.PrimaryKeyRelatedField(many=True)

    class Meta:
        model = Album
        fields = ('album_name', 'artist', 'tracks')

    def to_representation(self, instance):
        data = super(CreateAlbumSerializer, self).to_representation(instance)
        data['tracks'] = TrackSerializer(instance=instance.tracks).data
        return data
Run Code Online (Sandbox Code Playgroud)

对照

我个人喜欢方法#1而不是#2,即使它更冗长,因为它不会将任何自定义创建/响应逻辑泄漏给序列化程序.我认为序列化程序应该只知道如何序列化,并且应该在视图中完成为作业选择不同序列化程序的所有自定义要求.