在单个视图中序列化多个模型

7 投票
2 回答
21416 浏览
提问于 2025-04-18 06:47

这是一个场景:

我有两个模型:FileObj 和 DirObj。

class DirObj(models.Model):
    [...]
    parent = models.ForeignKey('self')
    [...]

class FileObj(models.Model):
    [...]
    parent = models.ForeignKey(DirObj)
    [...]

我还有以下的序列化器:

class FileObjSerializer(serializers.ModelSerializer):
    [...]
    class Meta:
        model = FileObj

class DirObjSerializer(serializers.HyperlinkedModelSerializer):
    [...]
    parent = serializers.HyperlinkedRelatedField(
        view_name = 'dirobj-detail')
    class Meta:
        model = DirObj

假设当用户访问 '/directories/[dir_id]' 时,我想在一个页面上返回由 'dir_id' 指定的 DirObj 的文件和目录内容,并且使用两个不同的序列化器。目前我有的(虽然不是完全一样,但大致上是这个意思)如下:

class DirContents(generics.GenericAPIView):
    def get(self, request, *args, **kwargs):
        files = FileObj.objects.filter(parent = kwargs.get('dir_id'))
        dirs = DirObj.objects.filter(parent = kwargs.get('dir_id'))
        files_serializer = FileObjSerializer(files, many = True)
        dirs_serializer = DirObjSerializer(dirs, many = True)
        response = files_serializer.data + dirs_serializer.data
        return Response(response)

这让我感觉像是一个很糟糕的解决办法。它也忽略了在浏览 API 时通常会显示的任何超链接(也就是说,HyperlinkedRelatedFields 并没有像应该那样显示为超链接)。有没有办法将任意数量的模型序列化并在一个视图中返回,而不破坏可浏览的 API,或者不需要做很多额外的工作来让超链接正常工作?

提前谢谢你!

2 个回答

-1

将文件添加到 DirObjSerializer 中,作为相关字段,并且要设置选项 many=True。想了解更多信息,可以查看这个链接:http://www.django-rest-framework.org/api-guide/relations

class DirObj(models.Model):
    [...]
    parent = models.ForeignKey('self')
    [...]

 class FileObj(models.Model):
    [...]
    parent = models.ForeignKey(DirObj, related_name='files')
    [...]


class FileObjSerializer(serializers.ModelSerializer):
    [...]
    class Meta:
        model = FileObj

class DirObjSerializer(serializers.HyperlinkedModelSerializer):
    [...]
    parent = serializers.HyperlinkedRelatedField(
        view_name = 'dirobj-detail')
    files = serializers.HyperlinkedRelatedField(many=True,
        view_name = 'fileobj-detail')

    class Meta:
        model = DirObj
15

你现在代码中遇到的问题,特别是链接无法正常工作,是因为你没有给序列化器传递任何上下文

class DirContents(generics.GenericAPIView):
    def get(self, request, *args, **kwargs):
        files = FileObj.objects.filter(parent=kwargs.get('dir_id'))
        dirs = DirObj.objects.filter(parent=kwargs.get('dir_id'))

        context = {
            "request": request,
        }

        files_serializer = FileObjSerializer(files, many=True, context=context)
        dirs_serializer = DirObjSerializer(dirs, many=True, context=context)

        response = files_serializer.data + dirs_serializer.data

        return Response(response)

对于使用混合类的通用视图,这个过程是自动完成的,但像你这种情况就需要手动传递上下文。

如果你是来这里想把两个模型合并成一个序列化器的:

在使用通用视图时,支持多个不同模型在一个视图中并没有简单的方法。看起来你并没有用它们来过滤查询集,所以其实是可以做到的,不过这种方式并不算“干净”。

class DirContents(generics.GenericAPIView):
    def get(self, request, *args, **kwargs):
        files = FileObj.objects.filter(parent=kwargs.get('dir_id'))
        dirs = DirObj.objects.filter(parent=kwargs.get('dir_id'))

        files_list = list(files)
        dirs_list = list(dirs)

        combined = files_list + dirs_list

        serializer = YourCombinedSerializer(combined, many=True)

        return Response(serializer.data)

撰写回答