orange1
orange1

Reputation: 2939

Django REST Framework -- destroy method won't take on URL params?

I am designing an API endpoint using Django REST Framework, and would like for it to accept GET and POST methods at the following endpoint:

companies/<company_pk>/membership

as well as DELETE methods at the following endpoint:

companies/<company_pk>/membership/<membership_pk>

There are two relevant models: Company and CompanyMembership. Each user can be a member of one or more companies,which is represented by an instance of CompanyMembership, which linked by a FK to Company.

I've created the appropriate GET and POST requests, but am having trouble with the DELETE requests -- it seems that the destroy method within my view is missing the membership_pk parameter, whether or not I define it within my URLs. How can I have my view accept DELETE requests which delete instances of CompanyMembership, which are identified by the membership_pk given in the URL?

urls.py

...
    url(r'^companies/(?P<company_pk>[0-9]+)/membership', include(company_urls.company_membership_router.urls,
        namespace='company_memberships')),
...

views.py


class CompanyMembershipViewSet(viewsets.ModelViewSet):
    """
    A ViewSet for creating, retrieving, and deleting CompanyMemberships.
    """
    queryset = CompanyMembership.objects.all()
    serializer_class = CompanyMembershipSerializer
    lookup_url_kwarg = 'company_pk'

    def get_queryset(self):
        uid = self.kwargs.get(self.lookup_url_kwarg)
        memberships = CompanyMembership.objects.filter(company_id=uid)
        return memberships

    def create(self, request, company_pk):
        """
        Custom create method since company_pk does not have to be sent
        explicitly within request.data

        Returns: instance of rest_framework Response.
        """
        EXISTING_USER_ERROR = {'non_field_errors':
            ['The fields user, company must make a unique set.']
        }
        data = {
            'user': request.data['user'],
            'company': company_pk
        }
        serializer = CompanyMembershipSerializer(data=data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data, status=status.HTTP_201_CREATED)
        if serializer.errors == EXISTING_USER_ERROR:
            return Response(serializer.errors, status=settings.ADDITIONAL_HTTP_STATUS_CODES['422_UNPROCESSABLE_ENTITY'])
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

    def destroy(self, request, **kwargs):
        company_membership = self.get_object(pk=membership_pk)
        company_membership.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)


routers.py
    from rest_framework import routers

    from .views import CompanyViewSet, CompanyMembershipViewSet


    company_router = routers.DefaultRouter()
    company_membership_router = routers.DefaultRouter()

    company_router.register(r'^', CompanyViewSet)
    company_membership_router.register(r'^', CompanyMembershipViewSet)

Upvotes: 1

Views: 3216

Answers (1)

Rahul Gupta
Rahul Gupta

Reputation: 47886

The company membership router generates the following urls:

companies/<company_pk>/membership/ # for handling list requests
companies/<company_pk>/membership/<pk>/ # for handling detail requests

You can access the membership_pk using the pk url kwarg .

Also, you have incorrectly defined lookup_url_kwarg field in your viewset. This kwarg is used by DRF to retrieve the object using get_object() method. You are not getting object because it is trying to perform lookup with pk as company_pk url kwarg value instead of pk value.

Upvotes: 1

Related Questions