如何在DRF的视图集中使用自定义列表方法和自定义动作?

时间:2018-12-18 00:29:12

标签: django django-rest-framework

从下面的代码中,您可以看到我使用了modelviewset,自定义list方法和名为get_recent_movies的自定义操作。

class MoviesViewSet(LoginRequiredMixin, ModelViewSet):
    authentication_classes = (authentication.SessionAuthentication,)
    permission_classes = (permissions.IsAuthenticated,)

    queryset = Movie.objects.all()
    serializer_class = MovieSerializer

    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,
                       rest_framework.filters.SearchFilter,
                        rest_framework.filters.OrderingFilter)
    filter_class = MovieFilter
    search_fields = {"title", "genre", "country", "language"}
    ordering_fields = ("title", "genre", "country", "language", "release_year", "timestamp")

    def get_queryset(self):
        queryset = Movie.objects.filter(user=self.request.user).select_related()
        return queryset

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        # Check for Datatables and server side processing parameters
        draw = self.request.query_params.get("draw", None)
        start = self.request.query_params.get("start", None)
        length = self.request.query_params.get("length", None)

        if draw and start and length:
            draw = int(draw)
            start = int(start)
            length = int(length)
            queryset = queryset[start:start+length]
            serializer = MovieListSerializer(queryset, many=True)
            result = {"draw": draw,
                      "recordsTotal": total_count,
                      "recordsFiltered": total_count,
                      "data": serializer.data}
            return Response(result)
        else:
            serializer = MovieListSerializer(queryset, many=True)
            return Response(serializer.data)


    @action(methods=["get"], detail=False,
            url_path="recent", url_name="recent")
    def get_recent_movies(self, request):
        queryset = self.filter_queryset(self.get_queryset())
        queryset = queryset.filter(status=1).order_by("-timestamp")[:12]
        serializer = MovieListSerializer(queryset, many=True)
        return Response(serializer.data)

使用自定义list方法的原因是我使用Datatables和服务器端处理,因此必须以正确的方式格式化数据。

我使用get_recent_movies获取用户最近看过的12部电影。

问题在于,get_recent_movies中的数据在显示在表中时需要格式化。我可以在自定义操作中重复使用list方法,但我不想这样做。

我不确定如何将查询集从自定义操作传递到列表方法。

2 个答案:

答案 0 :(得分:0)

尝试一下

class MoviesViewSet(LoginRequiredMixin, ModelViewSet):
    # your code

    def get_queryset(self):
        queryset = Movie.objects.filter(user=self.request.user).select_related()
        return queryset

    def check_data_tables(self, queryset):
        # Check for Datatables and server side processing parameters
        draw = self.request.query_params.get("draw", None)
        start = self.request.query_params.get("start", None)
        length = self.request.query_params.get("length", None)

        if draw and start and length:
            draw = int(draw)
            start = int(start)
            length = int(length)
            queryset = queryset[start:start + length]
            serializer = MovieListSerializer(queryset, many=True)
            return {"draw": draw,
                    "recordsTotal": total_count,
                    "recordsFiltered": total_count,
                    "data": serializer.data}
        return {}

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        result = self.check_data_tables(queryset)
        if result:
            return Response(result)
        else:
            serializer = MovieListSerializer(queryset, many=True)
            return Response(serializer.data)

    @action(methods=["get"], detail=False, url_path="recent", url_name="recent")
    def get_recent_movies(self, request):
        queryset = self.filter_queryset(self.get_queryset())
        queryset = queryset.filter(status=1).order_by("-timestamp")[:12]
        serializer = MovieListSerializer(queryset, many=True)
        """
        if some condtion:
            call check_data_tables() method
        """
        if condition:
            result = result = self.check_data_tables(queryset)
            return processed response
        return Response(serializer.data)

我在这里做了什么?
我创建了 check_data_tables() 的类方法,该方法对于两个操作 list get_recent_movies 使用 self

调用了该功能

答案 1 :(得分:0)

这是您实现目标的另一种方法:

class MoviesViewSet(LoginRequiredMixin, ModelViewSet):
    authentication_classes = (authentication.SessionAuthentication,)
    permission_classes = (permissions.IsAuthenticated,)

    queryset = Movie.objects.all()
    serializer_class = MovieSerializer

    filter_backends = (django_filters.rest_framework.DjangoFilterBackend,
                       rest_framework.filters.SearchFilter,
                        rest_framework.filters.OrderingFilter)
    filter_class = MovieFilter
    search_fields = {"title", "genre", "country", "language"}
    ordering_fields = ("title", "genre", "country", "language", "release_year", "timestamp")

    def get_queryset(self):
        queryset = Movie.objects.filter(user=self.request.user).select_related()

        if self.action == 'get_recent_movies':
             queryset = queryset.filter(status=1).order_by("-timestamp")[:12]

        return queryset


    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        # Check for Datatables and server side processing parameters
        draw = self.request.query_params.get("draw", None)
        start = self.request.query_params.get("start", None)
        length = self.request.query_params.get("length", None)

        if draw and start and length:
            draw = int(draw)
            start = int(start)
            length = int(length)
            queryset = queryset[start:start+length]
            serializer = MovieListSerializer(queryset, many=True)
            result = {"draw": draw,
                      "recordsTotal": total_count,
                      "recordsFiltered": total_count,
                      "data": serializer.data}
            return Response(result)
        else:
            serializer = MovieListSerializer(queryset, many=True)
            return Response(serializer.data)


    @action(methods=["get"], detail=False, url_path="recent", url_name="recent")
    def get_recent_movies(self, request, *args, **kwargs):
        return self.list(request, *args, **kwargs)

请注意get_queryset方法。在这里您可以控制要向自定义操作提供哪些数据。