如何在 django rest 框架中仅用一个视图处理 2 种不同类型的参数?

how you can handle 2 different types of arguments with only one view in django rest framework?

我有urls.py如下所示

urlpatterns = [
    path("watch-list/<int:pk>/", views.WatchItemDetail.as_view(), name="watch-detail"),
    path("watch-list/<str:slug>/", views.WatchItemDetail.as_view(), name="watch-detail-slug"),
]

所以我在同一路径中发送 2 个不同类型的参数,一个是 pk,也可以是 slug

在我的 views.py 中,我正在写 2 get 请求,我知道这不会起作用,因为 python 不支持方法的重载,所以我如何实现如下逻辑?我们也可以清理一些代码吗,因为我正在用同样的逻辑重复我自己。

class WatchItemDetail(APIView):

    def get(self, request, pk):
        watch_item = get_object_or_404(WatchItem, pk=pk)
        watch_item_serializer = WatchItemSerializer(watch_item)
        return Response(watch_item_serializer.data, status=status.HTTP_200_OK)

    def get(self, request, slug):
        watch_item = get_object_or_404(WatchItem, slug=slug)
        watch_item_serializer = WatchItemSerializer(watch_item)
        return Response(watch_item_serializer.data, status=status.HTTP_200_OK)

这仅适用于 slug 字段,因为上一个方法被下一个方法覆盖,但我希望它们都有效。

您可以检查类型并相应地工作:

class WatchItemDetail(APIView):

    def get(self, request, item):
        watch_item = get_object_or_404(WatchItem, pk=item) if isinstance(item, int) else get_object_or_404(WatchItem, slug=item)
        watch_item_serializer = WatchItemSerializer(watch_item)
        return Response(watch_item_serializer.data, status=status.HTTP_200_OK)

你可以试试这个:

class WatchItemDetail(APIView):

    def get(self, request, value):
        watch_item = get_object_or_404(WatchItem, pk=value) if isinstance(value, int) else get_object_or_404(WatchItem, slug=value)
        watch_item_serializer = WatchItemSerializer(watch_item)
        return Response(watch_item_serializer.data, status=status.HTTP_200_OK)

另一种方法是像这样同时捕获 pkslug kwargs:

from django.http import Http404


class WatchItemDetail(APIView):

    def get(self, request, pk=None, slug=None, *args, **kwargs):
        if pk is not None:
            watch_item = get_object_or_404(WatchItem, pk=pk)
        elif slug is not None:
            watch_item = get_object_or_404(WatchItem, slug=slug)
        else:
            raise Http404(f'No {WatchItem._meta.object_name} matches the given query.')

        watch_item_serializer = WatchItemSerializer(watch_item)
        return Response(watch_item_serializer.data, status=status.HTTP_200_OK)