orange1
orange1

Reputation: 2939

Django REST Framework -- update view method never called

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

Answers (2)

Rahul Gupta
Rahul Gupta

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

wobbily_col
wobbily_col

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

Related Questions