[Answered ]-Django rest framework 'NoneType' object is not callable

1πŸ‘

βœ…

By rebuilding a very small experimental project, I was able to solve this problem by understanding a series of problems below and I have put the form that you can properly do what you want here for you:

  1. It seems that this error you are receiving (Exception Value: 'NoneType' object is not callable) is related to the name of the detail (honestly, I have not understood the reason yet and I’m searching for it) and by changing it to any other name (really any other name πŸ˜„), this error will be resolved, according to your codes like this will be:

urls.py

    path('tasks/<int:pk>', views.TaskDetailViewset.as_view(        {
            'get':'any_other_thing'
        }))
]

views.py

class TaskDetailViewset(viewsets.ViewSet):

    def any_other_thing(self, request, pk): # you can send more params like *args or **kwrags and they are Ok
        ...
  1. After changing point 1 in your codes, with sending a request to mentioned url you’ll encounter the following error:
AssertionError: Cannot call `.is_valid()` as no `data=` keyword argument was passed when instantiating the serializer instance.

which will be solved by adding a data= argument name before task on the line where you build serializer:

    def any_other_thing(self, request, pk):
        ...
        serializer = TaskSerializer(data=task)
        ...
  1. After making the above change, you will still have problems in creating the serializer, and if you have made the serializer errors by placing the following line:
return Response(status=status.HTTP_404_NOT_FOUND)

In the code related to the view instead of

return Response(data=serializer.errors, status=status.HTTP_404_NOT_FOUND)

You can understand that now the error related to the non-field-error (Instead of passing a dictionary, you passed a "task" object):

{
    "non_field_errors": [
        "Invalid data. Expected a dictionary, but got Task."
    ]
}

By adding the following function with the task argument instead of passing the task directly to TaskSerializer, this problem will also be solved and you will finally be able to receive an answer successfully.

class TaskDetailViewset(viewsets.ViewSet):

    def any_other_thing(self, request, pk):
        ...
        serializer = TaskSerializer(data=model_to_dict(task))
        ...

Therefore, your code snippets will be as follows:

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('tasks', views.TaskViewset.as_view(
        {
            'get':'list',
            'post':'add',
            'put':'update',
            'delete':'delete'
        }
    )),
    path('tasks/<int:pk>', views.TaskDetailViewset.as_view(        {
            'get':'any_other_thing'
        }))
]

views.py

from django.forms.models import model_to_dict
from rest_framework.response import Response
from rest_framework import status, viewsets

from todo.models import Task
from todo.serilizers import TaskSerializer


class TaskDetailViewset(viewsets.ViewSet):

    def any_other_thing(self, request, pk, *args, **kwargs):
        #data = request.query_params
        task = Task.objects.get(id=pk)
        serializer = TaskSerializer(data=model_to_dict(task))

        if serializer.is_valid():
            return Response(data=serializer.data, status=status.HTTP_200_OK)
        return Response(data=serializer.errors, status=status.HTTP_404_NOT_FOUND)
πŸ‘€Javad

0πŸ‘

in last return add this:

return Response(serializer.errors, status=status.HTTP_404_NOT_FOUND)
πŸ‘€Hashem

0πŸ‘

I found a reason of my problem but still don’t get how it works.
The problem was in th name of my method detail. When I changed name to details everything started to work fine.

Now my urls.py looks like this

urlpatterns = [
    path('tasks', views.TaskViewset.as_view(
        {
            'get':'list',
            'post':'add',
            'put':'update',
            'delete':'delete'
        }
    )),
    path('tasks/<int:pk>', views.TaskDetailViewset.as_view(
        {
            'get': 'details'
            }
    ))
]

My TaskDetailViewset looks like this:

class TaskDetailViewset(viewsets.ViewSet):

    def details(self, request, pk):
        task = models.Task.objects.get(id=pk)
        serializer = serializers.TaskSerializer(data=task.__dict__)

        if serializer.is_valid():
            return Response(data=serializer.data, status=status.HTTP_200_OK)
        return Response(serializer.errors, status=status.HTTP_404_NOT_FOUND)

Thank you all for helping me!

πŸ‘€Aleksandr

Leave a comment