I am designing a REST API for an application that has both companies and departments. Some number of users can be members of a company. This leads to the following API structure:
/companies/
- Can GET, POST.
/companies/<pk>/
- Can GET, POST, PUTCH, PATCH, DELETE.
/companies/<pk>/membership/
- Can GET (gives all users that are members of a company), POST.
/companies/<pk>/membership/<pk>/
- Can DELETE.
I've managed to implement the first 3 of the endpoints, but am having trouble with implementing the last one -- how do I implement an endpoint that has multiple <pk>
values in the URL? Here's what I have so far:
Currently have a urls.py file in the api
app that looks as follows:
...
url(r'^company', include(company_urls.company_router.urls,
namespace="company")),
...
urls.py
in the company
application.
from rest_framework import routers
from .views import CompanyViewSet
company_router = routers.DefaultRouter()
company_router.register(r'^', CompanyViewSet)
serializers.py file:
from rest_framework import serializers
from .models import Company, CompanyMembership
from My_App.users.models import Profile
class CompanySerializer(serializers.ModelSerializer):
class Meta:
model = Company
fields = ('pk', 'name', 'departments', 'members')
read_only_fields = ('pk', 'departments', 'members')
class CompanyMembershipSerializer(serializers.Serializer):
user = serializers.PrimaryKeyRelatedField(queryset=Profile.objects.all())
def create(self, validated_data):
pass
def delete(self, instance, validated_data):
pass
And the views.py file:
from .models import Company, CompanyMembership
from .serializers import CompanySerializer, CompanyMembershipSerializer
from My_Appc.users.models import Profile
class CompanyViewSet(viewsets.ModelViewSet):
queryset = Company.objects.all()
serializer_class = CompanySerializer
@decorators.detail_route(methods=['get', 'post', 'delete'])
def membership(self, request, pk):
company = self.get_object()
if request.method == 'GET':
serializer = CompanyMembershipSerializer(company)
elif request.method == 'POST':
serializer = CompanyMembershipSerializer(data=request.data)
if serializer.is_valid():
try:
user = Profile.objects.get(pk=request.data.get('user'))
user_company_membership = CompanyMembership(user=user,
company=company)
user_company_membership.save()
return Response({'status': 'User added to Company.'},
status=status.HTTP_201_CREATED)
except IntegrityError:
result = {
'status': 'Failed to add user to Company.',
'reason': 'User already part of Company.'
}
status=settings.ADDITIONAL_HTTP_STATUS_CODES[
'422_UNPROCESSABLE_ENTITY']
return Response(result, status)
else:
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
Use different names for parameters in you url:
/companies/<company_pk>/membership/<membership_pk>/
And in you ViewSet add lookup_field
and lookup_url_kwarg
to point to company pk field/parameter:
class CompanyViewSet(viewsets.ModelViewSet):
lookup_field = 'pk'
lookup_url_kwarg = 'company_pk'
get_object
method uses this two lookups to filter queryset so you will get company based on first pk in url.
In your membership method and custom logic to manage membership object, you can access membership pk with:
membership_pk = self.kwargs.get('membership_pk', None)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With