Reputation: 2939
I am designing an API endpoint using Django REST Framework, and would like for it to accept GET, PATCH, and PUT methods at the following endpoint:
/department/<department_pk>/details/population/
there is a 1:1 relationship between the Department model and the DepartmentPopulationDetail model (the DepartmentPopulationDetail
model has a FK called departmnet
). The GET method should return the DepartmentPopulationDetail
model instance, and PUT and PATCH should allow one to edit that same instance (without needing to provide the DepartmentPopulationDetail
PK).
I've managed to have the endpoint return the desired response for GET and not allow DELETE or CREATE, but can't get it to accept PUT or PATCH requests -- in fact, the update
method is never called. How can I get my view to accept PUT and PATCH requests and to edit the appropriate model?
urls.py
...
url(r'^departments/(?P<department_pk>[0-9]+)/details/population',
include(department_urls.department_study_population_router.urls,
namespace='department_study_population')),
...
serializers.py
class DepartmentStudyPopulationSerializer(serializers.ModelSerializer):
class Meta:
model = DepartmentStudyPopulation
fields = ('pk', 'department', 'age', 'zip_code')
read_only_fields = ('pk', 'department')
views.py
class DepartmentStudyPopulationViewSet(viewsets.ModelViewSet):
queryset = DepartmentStudyPopulation.objects.all()
serializer_class = DepartmentStudyPopulationSerializer
http_method_names = ['get', 'put', 'patch']
def update(self, request, department_pk, **kwargs):
queryset = departmentStudyPopulation.objects.all()
study_population = get_object_or_404(queryset, department_pk=department_pk)
serializer = DepartmentStudyPopulationSerializer(
study_population, data=request.data, partial=True)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
Upvotes: 1
Views: 3094
Reputation: 47846
Why the update()
method never gets called?
This is because you have incorrectly defined the urls.
This url
'departments/(?P<department_pk>[0-9]+)/details/population'
with router generates the following urls.
'departments/(?P<department_pk>[0-9]+)/details/population/' # handle list views
'departments/(?P<department_pk>[0-9]+)/details/population/<pk>/' # handle detail views
So, your update()
method will only be called when there is a request on the below url where pk
represents the id
of DepartmentStudyPopulation
object.
'departments/(?P<department_pk>[0-9]+)/details/population/<pk>/'
How to handle the update
and retrieve
requests on the desired url then?
You need to make some changes to handle both update
and retrieve
requests on the below desired url endpoint.
/department/<department_pk>/details/population/
Firstly, you should use RetrieveUpdateAPIView
instead of ModelViewSet
as you need to handle only detail
routes. This generic view will only permit GET
, PUT
and PATCH
methods.
Secondly, you are getting the object instance using the department_pk
url kwarg by filtering on the department_pk
field and not the pk
field of DepartmentStudyPopulation
object. You should just specify the lookup_field
and lookup_url_kwarg
with value as department_pk
in your view and DRF will handle the instance retrieval.
Final Code:
views.py
class DepartmentStudyPopulationDetailView(generics.RetrieveUpdateAPIView):
queryset = DepartmentStudyPopulation.objects.all()
serializer_class = DepartmentStudyPopulationSerializer
lookup_field = 'department_pk'
lookup_url_kwarg = 'department_pk'
urls.py
url(r'^departments/(?P<department_pk>[0-9]+)/details/population', DepartmentStudyPopulationDetailView.as_view())
Upvotes: 4
Reputation: 11891
You will need a different URL to handle those cases.
Create means that your DepartmentStudyPopulation is new, and won't have a primary key (it gets generated on createion).
Update will require a url that has the primary key in it, so that Django knows what object to update.
(Showing the URL's file would be helpful for this question, as we have no idea where they are routing to).
Upvotes: 0