【问题标题】:Serialize multiple models in a single view在单个视图中序列化多个模型
【发布时间】:2014-07-05 05:48:24
【问题描述】:

这是场景:

我有两个模型; 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 和/或必须做(我假设的)一堆额外的工作才能使超链接正常工作?

提前致谢!

【问题讨论】:

    标签: python django django-rest-framework


    【解决方案1】:

    使用选项many=True 将文件添加到DirObjSerializer as realated 字段。 欲了解更多信息: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
    

    【讨论】:

    • 当然,但这会将 FileObjs 作为嵌套项返回。我不希望它们嵌套;我需要它们是独立的实体。此外,DirObj 已经有一个相对于 FileObj 上的“父”字段的相关字段。在此示例中,该相关字段将称为“fileobj”。
    【解决方案2】:

    您当前代码面临的问题,特别是链接不起作用的问题,是因为您不是序列化程序的passing in any context

    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)
    

    对于使用 mixin 的通用视图,这是自动完成的,但对于这种情况,需要手动传入。

    对于任何来这里将两个模型组合成一个序列化器的人:

    使用通用视图时,没有简单的方法可以在一个视图中支持多个不同的模型。看起来好像您没有使用它们来过滤查询集,所以这实际上是可以做到的,尽管不是以任何方式被认为是“干净”的。

    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)
    

    【讨论】:

    • 在上下文中传递确实修复了超链接。我将继续寻找一种干净的方法来序列化模型,但您的回答几乎回答了我的问题(并给了我更多阅读内容。)谢谢!
    • 这个解决方案给了我一个解决问题的好主意,谢谢
    猜你喜欢
    • 2018-09-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-03
    • 1970-01-01
    • 1970-01-01
    • 2020-02-19
    相关资源
    最近更新 更多