How can I register a single view (not a viewset) on my router?

后端 未结 2 1011
难免孤独
难免孤独 2020-11-29 20:33

I am using Django REST framework and have been trying to create a view that returns a small bit of information, as well as register it on my router.

I have four mode

相关标签:
2条回答
  • 2020-11-29 20:49

    There is one more way to do it:

    urlpatterns = [
        # ... 
        url(r'^you_path/', include(router.urls)),
        url(r'^you_path/you_sub_path', views.UpdateTimeView.as_view()),
        # ... 
    ]
    

    But stuff like Swagger will not work with that

    0 讨论(0)
  • 2020-11-29 21:05

    Routers work with a ViewSet and aren't designed for normal views, but that doesn't mean that you cannot use them with a normal view. Normally they are used with models (and a ModelViewSet), but they can be used without them using the GenericViewSet (if you would normally use a GenericAPIView) and ViewSet (if you would just use an APIView).

    For a list view, the request methods are mapped to ViewSet methods like this

    • GET -> list(self, request, format=None)
    • POST- > create(self, request, format=None)

    For detail views (with a primary key in the url), the request methods use the following map

    • GET -> retrieve(self, request, pk, format=None)
    • PUT -> update(self, request, pk, format=None)
    • PATCH -> partial_update(self, request, pk, format=None)
    • DELETE -> destroy(self, request, pk, format=None)

    So if you want to use any of these request methods with your view on your router, you need to override the correct view method (so list() instead of get()).


    Now, specifically in your case you would have normally use an APIView that looked like

    class UpdateTimeView(APIView):
    
        def get(self, request, format=None):
            latest_publish = Publish.objects.latest('created_time')
            latest_meeting = Meeting.objects.latest('created_time')
            latest_training = Training.objects.latest('created_time')
            latest_exhibiting = Exhibiting.objects.latest('created_time')
    
            return Response({
                "publish_updatetime": latest_publish.created_time,
                "meeting_updatetime": latest_meeting.created_time,
                "training_updatetime": latest_training.created_time,
                "exhibiting_updatetime": latest_exhibiting.created_time,
            })
    

    The comparable ViewSet would be

    class UpdateTimeViewSet(ViewSet):
    
        def list(self, request, format=None):
            latest_publish = Publish.objects.latest('created_time')
            latest_meeting = Meeting.objects.latest('created_time')
            latest_training = Training.objects.latest('created_time')
            latest_exhibiting = Exhibiting.objects.latest('created_time')
    
            return Response({
                "publish_updatetime": latest_publish.created_time,
                "meeting_updatetime": latest_meeting.created_time,
                "training_updatetime": latest_training.created_time,
                "exhibiting_updatetime": latest_exhibiting.created_time,
            })
    

    Notice the two required changes: APIView -> ViewSet and get -> list. I also updated the name to indicate that it was more than just a normal view (as a ViewSet cannot be initialized the same way), but that's not required.

    So with this new view, you can just register it in the router the same way as any other. You need a base_name here so the url names can be generated (normally this would pull from the queryset).

    router.register(r'updatetime', views.UpdateTimeViewSet, base_name='updatetime')
    

    So now the updatetime endpoint will be made available in the API root and you can get the latest times by just calling the endpoint (a simple GET request).

    0 讨论(0)
提交回复
热议问题