0

我在 DRF 中有以下 4 个基于类的视图来对名为 Trips 的模型执行 CRUD 操作。

from rest_framework import generics

class TripCreateView(CreateAPIView): 
    #code that creates a Trip

class TripListView(ListAPIView):
    #code that lists Trips

class TripDetailView(RetrieveAPIView):
    #code that gives details of a Trip

class TripUpdateView(UpdateAPIView):
    #code that updates a particular trip details

class TripDeleteView(DestroyAPIView):
    #code that deletes an instance

现在为了将 url 连接到每个视图,我的 urls.py 看起来像这样:

urlpatterns = [
url(r'^trip/$', TripCreateView.as_view()),
url(r'^trip/list/$',TripListView.as_view()),
url(r'^trip/(?P<pk>[0-9]+)/detail/$', TripDetailView.as_view()),
url(r'^trip/(?P<pk>[0-9]+)/update/$', TripUpdateView.as_view()),
url(r'^trip/(?P<pk>[0-9]+)/delete/$', TripDeleteView.as_view())
]

这按预期工作。但是,很明显,这些 API 端点设计得很糟糕,因为 URI 中也有 http 方法。RESTFUL API 端点在 URI 中没有 HTTP 方法,如下所示:

Endpoint             HTTP METHOD          Result
trips                GET                Gets all Trips
trips/:id            GET                Gets details of a Trip
trips                POST               Creates a Trip
trips/:id            PUT                Updates a Trip
trips:/id            DELETE             Deletes a Trip

我知道 Viewsets 可以帮助实现这一点,但由于某些其他限制,我无法使用它们。这可以通过使用我正在使用的基于类的视图来实现吗?

4

1 回答 1

0

很惊讶这个没有收到答案。

这与 HTTP 动词以及 Django Rest 框架如何映射它们有关。

无论如何,你会优先想要像你的视图集这样的东西:

from rest_framework import (
    mixins,
    viewsets
)

from trips.models import Trip
from trips.api.serializers import TripSerializer

class TripView(
    viewsets.GenericViewSet,
    mixins.ListModelMixin,
    mixins.CreateModelMixin,
    mixins.RetrieveModelMixin,
    mixins.UpdateModelMixin,
    mixins.DestroyModelMixin,
):

    queryset = Trip.objects.all()
    serializer_class = TripSerializer

    """
    Example empty viewset demonstrating the standard
    actions that will be handled by a router class.

    If you're using format suffixes, make sure to also include
    the `format=None` keyword argument for each action.
    """

    def list(self, request):
        pass

    def create(self, request):
        pass

    def retrieve(self, request, pk=None):
        pass

    def update(self, request, pk=None):
        pass

    def destroy(self, request, pk=None):
        pass

更多信息在这里:https ://www.django-rest-framework.org/api-guide/viewsets/

如果做不到这一点,你可以修改这些代码行:

urlpatterns = [
    url(r'^trips/$',TripListView.as_view({'get': 'list'})),
    url(r'^trips/$', TripCreateView.as_view({'post': 'create'})),
    url(r'^trips/(?P<pk>[0-9]+)/$', TripDetailView.as_view({'get': 'retrieve'})),
    url(r'^trips/(?P<pk>[0-9]+)/$', TripUpdateView.as_view({'put': 'update'})),
    url(r'^trips/(?P<pk>[0-9]+)/$', TripDeleteView.as_view({'delete': 'destroy'}))
]

也就是说,您有一个基本端点http://example.com/api/v1/trips,然后每个操作都不是通过将其附加到 url 而是通过您正在使用的 http 动词来映射的。最佳实践是在基本端点上有一个 get 和一个 post,一个“列表”,另一个将“创建”(要创建,您必须将一个完全 JSON 序列化的对象发布到创建端点)。因此,使用这两个动词,您可以使用相同的端点但用于不同的资源操作。

检索、更新和销毁端点也是如此。这些操作的端点是相同的:类似于http://example.com/api/v1/trips/<uuid:uuid>或的东西http://example.com/api/v1/trips/<id:id>,本质上与上面相同,但有一个额外的空间用于传递一些主键,因此服务器知道您的目标是哪个对象。同样,每个动作都由您使用的 HTTP 动词动作区分,因此对于检索、更新和销毁,您需要将获取、放置或删除动词传递给请求端点。

希望这是有道理的!

于 2021-05-10T08:03:52.047 回答