Daniel
Daniel

Reputation: 534

How to allow POST for update action in django rest framework

We're building an API with Django Rest Framework, and our clients want it to have this endpoint:

Method: POST
URL: api/v1/application/<id>

It's basically an update endpoint but with POST instead of PUT.

I already have a viewset for this model, and we're using the create, list, and retrieve actions.

So, one thing I can do is to allow POST for update actions in Django Rest Framework, but I haven't found how to do that. Also, I can define a custom action like this:

@action(methods=['post'], detail=True)
def update_status(self, request, pk=None):
    # some code

The problem is this routes to application/<id>/update_status, I can change the route by passing the url_path parameter, but if it's None or empty it just defaults to update_status again.

I can also just define this endpoint in a different view and route manually, but that's a worse solution in my opinion, it would be nice to have it in the viewset I already have.

Thanks.

Upvotes: 6

Views: 4713

Answers (2)

Lucas Weyne
Lucas Weyne

Reputation: 1152

Django REST framework allows binding viewsets to URLs explicitly. You can create a set of views from your viewset and bind the URLs without a router

views.py

from restframework import viewsets, mixins

class ApplicationViewSet(mixins.ListModelMixin,
                         mixins.RetrieveModelMixin,
                         mixins.CreateModelMixin,
                         viewsets.GenericViewSet):
    # Your viewset settings 

    def update(self, request, pk=None):
        # Your code

urls.py

from django.urls import path, include

from .views import ApplicationViewSet


app_list = ApplicationViewSet.as_view({
    'get': 'list',
    'post': 'create'
})
app_detail = ApplicationViewSet.as_view({
    'get': 'retrieve',
    'post': 'update',  # POST instead PUT
})


urlpatterns = [
    path('application/', app_list, name='application-list'),
    path('application/<int:pk>/', app_detail, name='application-detail'),
]

Upvotes: 3

whytheplatypus
whytheplatypus

Reputation: 189

I just had to do this and found that this works when setting up the router in urls.py:

router = routers.SimpleRouter()
# Post Edit route.
router.routes[2].mapping['post'] = 'partial_update'
router.register(r'things', ThingViewSet)

The alternative is you build your own Router. Which isn't to bad either.

For reference here's the bit of code that defines the array this changes.

Upvotes: 1

Related Questions