Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django REST Framework - pass extra parameter to actions

I'm using Django 2.0 and Django REST Framework

I have created an action method to delete particular object from database

contacts/views.py

class ContactViewSet(viewsets.ModelViewSet):
    serializer_class = ContactSerializer
    permission_classes = (IsAuthenticated, AdminAuthenticationPermission,)

    # others actions goes here

    @action(methods=['delete'], detail=False, url_path='delete_phone/<phone_pk>/')
    def delete_phone(self, request, pk=None):
        contact = self.get_object()
        print(contact)
        print(pk)
        print(self.kwargs['phone_pk'])
        return Response({'status': 'success'})

apps/urls.py

router.register(r'contacts', ContactViewSet, 'contacts')

api_urlpatterns = [
    path('', include(router.urls)),
]

But when I access

DELETE: http://url/api/contacts/delete_phone/1/

It gives page not found error.

In the error page, there is listing in tried url patterns

api/ ^contacts/delete_phone/<phone_pk>//$ [name='contacts-delete-phone']
api/ ^contacts/delete_phone/<phone_pk>\.(?P<format>[a-z0-9]+)/?$ [name='contacts-delete-phone']
like image 726
Anuj TBE Avatar asked May 19 '18 12:05

Anuj TBE


People also ask

How do I pass extra data to a serializer?

In function-based views, we can pass extra context to serializer with “context” parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with “self. context”. From example, to get “exclude_email_list” we just used code 'exclude_email_list = self.

What is ViewSet in Django REST framework?

Django REST framework allows you to combine the logic for a set of related views in a single class, called a ViewSet . In other frameworks you may also find conceptually similar implementations named something like 'Resources' or 'Controllers'.

What is Django MultiPartParser?

MultiPartParser. Parses multipart HTML form content, which supports file uploads. Both request. data will be populated with a QueryDict .


2 Answers

In case you can't/don't want/whatever install drf-nested-routers, you could achieve the same by doing:

@action(detail=True,
        methods=['delete'],
        url_path='contacts/(?P<phone_pk>[^/.]+)')
def delete_phone(self, request, phone_pk, pk=None):
    contact = self.get_object()
    phone = get_object_or_404(contact.phone_qs, pk=phone_pk)
    phone.delete()
    return Response(.., status=status.HTTP_204_NO_CONTENT)

The trick is to put the regex in url_path parameter of the decorator and pass it to the decorated method (avoid using just pk or it will collide with the first pk)

Tested with:

Django==2.0.10
djangorestframework==3.9.0
like image 146
diegueus9 Avatar answered Sep 30 '22 14:09

diegueus9


Solved the problem using drf-nested-routers

For those who need it, install the plugin and configure urls.py

from rest_framework_nested import routers

router = routers.SimpleRouter()
router.register(r'contacts', ContactViewSet, 'contacts')
contact_router = routers.NestedSimpleRouter(router, r'contacts', lookup='contact')
contact_router.register(r'phone_number', ContactPhoneNumberViewSet, base_name='contact-phone-numbers')

api_urlpatterns = [
    path('', include(router.urls)),
    path('', include(contact_router.urls))
]
like image 20
Anuj TBE Avatar answered Sep 30 '22 12:09

Anuj TBE