Django.fun

Django / Django Rest Framework ModelViewSet: __init__() takes 1 positional argument but 2 were given

I'm trying to create a custom "list" under OptionViewSet but It's giving me an error.

class OptionViewSet(viewsets.ModelViewSet):
    serializer_class = OptionSerializer
    queryset = Option.objects.all()

    def list(self, request):
        queryset = Option.objects.all()
        serializer = OptionSerializer(queryset, many=True)
        return Response(serializer.data)

Error

__init__() takes 1 positional argument but 2 were given

This works fine:

class OptionViewSet(viewsets.ModelViewSet):
    serializer_class = OptionSerializer
    queryset = Option.objects.all()

urls.py

path('api/shipping/', include((shipping_routes.urls, 'shipping'), namespace='shipping')),

routes.py

routes.register(r'option', OptionViewSet, basename='option')

serializer

class OptionSerializer(serializers.ModelSerializer):
    class Meta:
        model = Option
        fields = ['id', 'extra', 'name']

full traceback

Traceback (most recent call last):
  File "C:\Users\Simon\.virtualenvs\django_backend-ZmgaAA1F\lib\site-packages\django\core\handlers\exception.py", line 47, in inner
    response = get_response(request)
  File "C:\Users\Simon\.virtualenvs\django_backend-ZmgaAA1F\lib\site-packages\django\core\handlers\base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "C:\Users\Simon\.virtualenvs\django_backend-ZmgaAA1F\lib\site-packages\django\views\decorators\csrf.py", line 54, in wrapped_view
    return view_func(*args, **kwargs)
  File "C:\Users\Simon\.virtualenvs\django_backend-ZmgaAA1F\lib\site-packages\rest_framework\viewsets.py", line 125, in view
    return self.dispatch(request, *args, **kwargs)
  File "C:\Users\Simon\.virtualenvs\django_backend-ZmgaAA1F\lib\site-packages\rest_framework\views.py", line 509, in dispatch
    response = self.handle_exception(exc)
  File "C:\Users\Simon\.virtualenvs\django_backend-ZmgaAA1F\lib\site-packages\rest_framework\views.py", line 469, in handle_exception
    self.raise_uncaught_exception(exc)
  File "C:\Users\Simon\.virtualenvs\django_backend-ZmgaAA1F\lib\site-packages\rest_framework\views.py", line 480, in raise_uncaught_exception
    raise exc
  File "C:\Users\Simon\.virtualenvs\django_backend-ZmgaAA1F\lib\site-packages\rest_framework\views.py", line 506, in dispatch
    response = handler(request, *args, **kwargs)
  File "C:\Users\Simon\Documents\GitHub\crud-react-django\django_backend\shipping\views.py", line 18, in list
    return Response(serializer.data)

Exception Type: TypeError at /api/shipping/option/
Exception Value: __init__() takes 1 positional argument but 2 were given

In the url.py, in the the specific path from urlpatters[] you need to call your views.OptionViewSet.as_view() as a middle parameter between the URL path and the name reference:

path('api/shipping/', include((shipping_routes.urls, 'shipping'), namespace='shipping')),

Django has very good documentation and you can read more about the Django-Rest-Framework's ViewSets here: https://www.django-rest-framework.org/api-guide/viewsets/

The viewsets.ModelViewSet provides the complete set of create/list/retrieve/update/destroy actions by default, If you want a custom list then I believe you should consider Custom ViewSet base classesto customize the behaviour.

Example:

from rest_framework import mixins

class CreateListRetrieveViewSet(mixins.CreateModelMixin,
                                mixins.ListModelMixin,
                                mixins.RetrieveModelMixin,
                                viewsets.GenericViewSet):
    """
    A viewset that provides `retrieve`, `create`, and `list` actions.

    To use it, override the class and set the `.queryset` and
    `.serializer_class` attributes.
    """
    pass

Source

So if we modify your Code according to that approach that should look like this;

class OptionViewSet(mixins.ListModelMixin, viewsets.GenericViewSet):
    serializer_class = OptionSerializer
    queryset = Option.objects.all()

    def list(self, request):
        queryset = Option.objects.all()
        serializer = OptionSerializer(queryset, many=True)
        return Response(serializer.data)

If you want to extend the ModelViewSet then you can follow the docs related to Marking extra actions for routing. According to that approach OptionViewSet should be like this:

class OptionViewSet(viewsets.ModelViewSet):
    serializer_class = OptionSerializer
    queryset = Option.objects.all()
    
    # ... 
    @action(detail=False, methods=['get'])
    def custom_list(self, request):
        queryset = Option.objects.all()
        serializer = OptionSerializer(queryset, many=True)
        return Response(serializer.data)

I had the wrong Response import. Imported it from "requests" instead of "rest_framework.response".

Tutorials

Современный Python: начинаем проект с pyenv и poetry

Настройка проекта Python — виртуальные среды и управление пакетами

Использование requests в Python — тайм-ауты, повторы, хуки

Понимание декораторов в Python

ProcessPoolExecutor в Python: полное руководство

map() против submit() с ProcessPoolExecutor в Python

Понимание атрибутов, словарей и слотов в Python

Полное руководство по slice в Python

Выпуск Django 4.0

Безопасное развертывание приложения Django с помощью Gunicorn, Nginx и HTTPS

Автоматический повтор невыполненных задач Celery

Django REST Framework и Elasticsearch

Докеризация Django с помощью Postgres, Gunicorn и Nginx

Асинхронные задачи с Django и Celery

Релизы безопасности Django: 3.2.4, 3.1.12 и 2.2.24

Выпуски исправлений ошибок Django: 3.2.3, 3.1.11 и 2.2.23

Эффективное использование сериализаторов Django REST Framework

Выпуски безопасности Django: 3.2.2, 3.1.10 и 2.2.22

Выпущенные релизы безопасности Django: 3.2.1, 3.1.9 и 2.2.21

Обработка периодических задач в Django с помощью Celery и Docker

View all tutorials →