具有基于Django Rest Framework类的视图的RestFul API端点

时间:2018-11-20 10:43:02

标签: python django django-rest-framework django-urls django-rest-viewsets

我在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())
]

这可以按预期工作。但是,很明显,由于URI中也带有http方法,因此这些API端点的设计不佳。 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可以帮助实现这一点,但是由于某些其他限制,我不能使用它们。仅使用我正在使用的基于类的视图就可以实现吗?

1 个答案:

答案 0 :(得分:0)

很惊讶这个人没有收到答复。

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

无论如何,你会优先为你的视图集想要类似的东西:

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 动词操作进行区分,因此对于检索、更新和销毁,您需要将 get、put 或 delete 动词传递给请求端点。

希望这是有道理的!