在单个视图中序列化多个模型
这是一个场景:
我有两个模型: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)