1

Preface

Django developer turns to Django REST framework developer, you will find that there is Django based on the original urlpatterns path of 061c1981b75264.
Originally I thought that the Django part would use the urlpatterns path, and the DRF part would be the router.register, but later look at the Django REST framework official document ( Tutorial 3: Class-based Views-English document | Tutorial 3: Class-based Views- Chinese document ), I found that things are not so simple.

content

Traditional way

Let me talk about the conclusion first, when the api we developed is inherited from APIView , then use the traditional Django CBV , and register the route in the urlpatterns path by calling the as_view method, just like the example in the official document

from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

urlpatterns = [
    url(r'^snippets/$', views.SnippetList.as_view()),
    url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()),
]

urlpatterns = format_suffix_patterns(urlpatterns)

SnippetDetail is defined as follows:

class SnippetDetail(APIView):
    """
    检索,更新或删除一个snippet示例。
    """
    def get_object(self, pk):
        try:
            return Snippet.objects.get(pk=pk)
        except Snippet.DoesNotExist:
            raise Http404

    def get(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet)
        return Response(serializer.data)

    def put(self, request, pk, format=None):
        snippet = self.get_object(pk)
        serializer = SnippetSerializer(snippet, data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def delete(self, request, pk, format=None):
        snippet = self.get_object(pk)
        snippet.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

New way

The inheritance exclusive Django REST framework of ViewSet , is used router.register registered routes.

Inherited from ModelViewSet or GenericViewSet with ViewSet as the suffix are counted.

For details, Django REST framework refer to the official document (161c1981b7546b Tutorial 6: ViewSets & Routers-English document | Tutorial 6: ViewSets & Routers-Chinese document )

Extract the key code below

from django.urls import path, include
from rest_framework.routers import DefaultRouter
from snippets import views

# Create a router and register our viewsets with it.
router = DefaultRouter()
router.register(r'snippets', views.SnippetViewSet)
router.register(r'users', views.UserViewSet)

# The API URLs are now determined automatically by the router.
urlpatterns = [
    path('', include(router.urls)),
]

The definition of SnippetViewSet is as follows, you can see that SnippetViewSet is inherited from ModelViewSet

from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework import permissions
from rest_framework import viewsets

class SnippetViewSet(viewsets.ModelViewSet):
    """
    This viewset automatically provides `list`, `create`, `retrieve`,
    `update` and `destroy` actions.

    Additionally we also provide an extra `highlight` action.
    """
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer
    permission_classes = [permissions.IsAuthenticatedOrReadOnly,
                          IsOwnerOrReadOnly]

    @action(detail=True, renderer_classes=[renderers.StaticHTMLRenderer])
    def highlight(self, request, *args, **kwargs):
        snippet = self.get_object()
        return Response(snippet.highlighted)

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)

The relationship between the two ways

Django's urlpatterns path and Django REST framework's router.register are not opposites, and there is no need to choose one of DRF . The method of Django method. As for why such packaging is required for better organization api
Similarly, we can use the traditional as_view ViewSet . This is explained in detail in the appeal document. The general meaning is to explicitly state the action as_view method. This parameter is a dictionary type, and declares such as get , Post, patch and other methods and the mapping relationship between specific functions.

from snippets.views import SnippetViewSet, UserViewSet, api_root
from rest_framework import renderers

snippet_list = SnippetViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
snippet_detail = SnippetViewSet.as_view({
    'get': 'retrieve',
    'put': 'update',
    'patch': 'partial_update',
    'delete': 'destroy'
})
snippet_highlight = SnippetViewSet.as_view({
    'get': 'highlight'
}, renderer_classes=[renderers.StaticHTMLRenderer])
user_list = UserViewSet.as_view({
    'get': 'list'
})
user_detail = UserViewSet.as_view({
    'get': 'retrieve'
})

universe_king
3.5k 声望716 粉丝