如何使用相同型号的两个不同型号的序列化器?

时间:2014-02-21 21:44:48

标签: python json django rest django-rest-framework

我正在使用django-rest-framework。我有一个有关系的模型。我想在用户点击/modelname/网址时显示相关项的计数,但在用户点击/modelname/1/处的特定模型实例时显示完整的相关集。

几乎得到我想要的东西。

我有两个序列化器,如下:

class DataSetSerializer(serializers.ModelSerializer):
    revisions = serializers.RelatedField(source='datasetrevision_set', many=True)

    class Meta:
        model = DataSet
        fields = ('id', 'title', 'revisions')

class ShortDataSetSerializer(serializers.ModelSerializer):

    class Meta:
        model = DataSet
        fields = ('id', 'title', 'revisions')

如果我使用短版本,我会得到修订计数(这是一个计算字段)。如果我使用长版本,我会将相关项目的完整列表作为“修订版”。

短:

[{"id": 1, "title": "My Data Set", "revisions": 0}]

长:

[{"id": 1, "title": "My Data Set", "revisions": ["Data Set v1", "Data Set v2"]}]

我想要做的是能够根据查询参数(url)在它们之间切换。当ID不存在时,我尝试将serializer_class设置为ShortDataSetSerializer,但它覆盖了所有情况,而不仅仅是非ID情况。

class DataSetViewSet(viewsets.ModelViewSet):
    serializer_class = DataSetSerializer
    model = DataSet

    def get_queryset(self):
       try:
           id = self.kwargs['id']
           queryset = DataSet.objects.filter(id=id)
       except KeyError:
           queryset = DataSet.objects.all()
           # We want to only list all of the revision data if we're viewing a
           # specific set, but this overrides for all cases, not just the one
           # we want.
           self.serializer_class = ShortDataSetSerializer
       return queryset

我有办法让这项工作成功吗?我意识到我可能会以一种完全荒谬的方式接近这一点,但似乎应该有一个简单的解决方案。

与我正在使用的真实数据相比,我提供的数据示例相当简短。最终目标是在列表视图中显示字段的子集,并在GET中显示特定ID的每个字段。这是一个只读API,所以我不需要担心POST / PUT / DELETE。

3 个答案:

答案 0 :(得分:3)

您可以通过覆盖get_serializer_class方法来完成此操作:

class DataSetViewSet(viewsets.ModelViewSet):
    model = DataSet

    def get_queryset(self):
       queryset = DataSet.objects.all()
       if self.kwargs.get('id'):
          queryset = queryset.filter(pk=self.kwargs.get('id'))
       return queryset

    def get_serializer_class(self):
       return DataSetSerializer if 'id' in self.kwargs else ShortDataSetSerializer

答案 1 :(得分:1)

我认为这个问题的一个简单解决方案是使用基于类的通用视图而不是视图集。

您可以使用list create_class作为ShortDataSetSerializer创建api视图。因此,当您获得数据列表时,它将具有修订计数。此外,如果您希望post请求在同一个url上工作,则必须覆盖get_serializer_class方法,以根据请求类型设置serializer_class。

对于检索视图,您可以将serializer_class用作DataSetSerializer。它将有一个修订列表而不是计数。

在DRF docs网站上查看通用视图api指南。

此外,您可以覆盖视图集上的列表并检索方法,但我更喜欢使用基于类的视图,因为DRF在请求函数(如get,put等)上附加了许多附加功能(或列表,详细信息) )最好不要覆盖它们。

答案 2 :(得分:0)

谢谢你,本杰明。这没有做我想要的。最终我要做的就是这个(使用与上面相同的序列化器):

class DataSetViewSet(viewsets.ModelViewSet):
    model = DataSet

    def list(self, request):
        queryset = DataSet.objects.all()
        serializer = ShortDataSetSerializer(queryset, many=True)
        return Response(serializer.data)

    def detail(self, request, id=None):
        queryset = DataSet.objects.get(id=id)
        serializer = DataSetSerializer(queryset)
        return Response(serializer.data)

在urls.py中:

url(r'^sets/$', views.DataSetViewSet.as_view({'get': 'list'})),
url(r'^sets/(?P<id>\d+)/$', views.DataSetViewSet.as_view({'get': 'detail'})),