Django viewset has not attribute 'get_extra_actions'
Solution 1
You've called it a viewset, but that doesn't make it one; you inherit from APIView which is a standalone generic view, not a viewset.
A viewset needs to inherit from viewsets.ViewSet.
Solution 2
Before Django Rest Framework v3.8 you could register an APIView
directly with a router. I did this extensively to gain a nice collated (and versioned) auto-documenting API for some very custom API endpoints. Given the choice again, I would probably write the whole thing a more standard way, but that isn't an option for everybody.
But after digging into the error, it turns out you can just patch over the problem by giving the router what it wants and adding a dummy get_extra_actions
classmethod.
class MyAPIView(APIView):
@classmethod
def get_extra_actions(cls):
return []
#...
I'm not saying this is good, but it works for now.
I've got my documentation back and I've managed to upgrade to DRFv3.8.
Solution 3
For:
djangorestframework==3.11.0
Django==2.2.9
You need to change class SessionViewSet(APIView):
to:
from rest_framework import mixins, viewsets
class SessionViewSet(mixins.ListModelMixin,
viewsets.GenericViewSet):
To get it to work. The internals of DRF have changed a bit and the other solutions won't cut it any longer.
Solution 4
In views.py, your viewset have to inherit from viewset and use it in your viewset try code below:
class SessionViewSet(viewsets.ModelViewSet):
queryset = Session.objects.all()
serializer_class = SessionSerializer
def get(self, request, format=None):
return Response("test")
Solution 5
Beware of using the same names for your viewset class and your model class. This was the reason for my own error. See example of what i did
# inside member/views.py
from member.models import Member
# inheriting from model viewset but called Member
class Member(viewsets.ModelViewSet):
queryset = Member.objects.all()
...
# inside urls.py
from member.views import Member
router = routers.DefaultRouter()
router.register(r'member', Member)
Now the mistake here is its importing the member model instead of the viewset but they are of the same names
Related videos on Youtube
alexca
Updated on July 09, 2022Comments
-
alexca almost 2 years
I am working with Django for a first time and I'm trying to build an API and I am following some tutorials and examples and it works right, but I am running the project now in a Raspberry Pi after install all the requirements and the project is failing with the following error:
Performing system checks... Unhandled exception in thread started by <function check_errors.<locals>.wrapper at 0xb547adb0> Traceback (most recent call last): File "/home/pi/.local/lib/python3.5/site-packages/django/utils/autoreload.py", line 225, in wrapper fn(*args, **kwargs) File "/home/pi/.local/lib/python3.5/site-packages/django/core/management/commands/runserver.py", line 120, in inner_run self.check(display_num_errors=True) File "/home/pi/.local/lib/python3.5/site-packages/django/core/management/base.py", line 364, in check include_deployment_checks=include_deployment_checks, File "/home/pi/.local/lib/python3.5/site-packages/django/core/management/base.py", line 351, in _run_checks return checks.run_checks(**kwargs) File "/home/pi/.local/lib/python3.5/site-packages/django/core/checks/registry.py", line 73, in run_checks new_errors = check(app_configs=app_configs) File "/home/pi/.local/lib/python3.5/site-packages/django/core/checks/urls.py", line 13, in check_url_config return check_resolver(resolver) File "/home/pi/.local/lib/python3.5/site-packages/django/core/checks/urls.py", line 23, in check_resolver return check_method() File "/home/pi/.local/lib/python3.5/site-packages/django/urls/resolvers.py", line 397, in check for pattern in self.url_patterns: File "/home/pi/.local/lib/python3.5/site-packages/django/utils/functional.py", line 36, in __get__ res = instance.__dict__[self.name] = self.func(instance) File "/home/pi/.local/lib/python3.5/site-packages/django/urls/resolvers.py", line 536, in url_patterns patterns = getattr(self.urlconf_module, "urlpatterns", self.urlconf_module) File "/home/pi/.local/lib/python3.5/site-packages/django/utils/functional.py", line 36, in __get__ res = instance.__dict__[self.name] = self.func(instance) File "/home/pi/.local/lib/python3.5/site-packages/django/urls/resolvers.py", line 529, in urlconf_module return import_module(self.urlconf_name) File "/usr/lib/python3.5/importlib/__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 986, in _gcd_import File "<frozen importlib._bootstrap>", line 969, in _find_and_load File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 673, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 673, in exec_module File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed File "/home/pi/Projects/openvpn-monitor/openvpnmonitor/urls.py", line 24, in <module> url(r'^api/', include('openvpnmonitor.api.urls')), File "/home/pi/.local/lib/python3.5/site-packages/django/urls/conf.py", line 34, in include urlconf_module = import_module(urlconf_module) File "/usr/lib/python3.5/importlib/__init__.py", line 126, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "<frozen importlib._bootstrap>", line 986, in _gcd_import File "<frozen importlib._bootstrap>", line 969, in _find_and_load File "<frozen importlib._bootstrap>", line 958, in _find_and_load_unlocked File "<frozen importlib._bootstrap>", line 673, in _load_unlocked File "<frozen importlib._bootstrap_external>", line 673, in exec_module File "<frozen importlib._bootstrap>", line 222, in _call_with_frames_removed File "/home/pi/Projects/openvpn-monitor/openvpnmonitor/api/urls.py", line 16, in <module> urlpatterns += router.urls File "/home/pi/.local/lib/python3.5/site-packages/rest_framework/routers.py", line 101, in urls self._urls = self.get_urls() File "/home/pi/.local/lib/python3.5/site-packages/rest_framework/routers.py", line 363, in get_urls urls = super(DefaultRouter, self).get_urls() File "/home/pi/.local/lib/python3.5/site-packages/rest_framework/routers.py", line 261, in get_urls routes = self.get_routes(viewset) File "/home/pi/.local/lib/python3.5/site-packages/rest_framework/routers.py", line 176, in get_routes extra_actions = viewset.get_extra_actions() AttributeError: type object 'SessionViewSet' has no attribute 'get_extra_actions'
My views.py has the following code:
from django.shortcuts import render from rest_framework import viewsets from .models import Session from .serializers import SessionSerializer from rest_framework.views import APIView, Response class SessionViewSet(APIView): queryset = Session.objects.all() serializer_class = SessionSerializer def get(self, request, format=None): return Response("test")
I really don't know why is working on my laptop but it is not working on my Raspberry Pi.
Has this happened to someone or anyone knows why is happening this?
Thank you so much!
Edit:
Here is my urls.py
from django.conf.urls import url from rest_framework import routers from openvpnmonitor.api.views import SessionViewSet router = routers.DefaultRouter() router.register(r'sessions', SessionViewSet) urlpatterns = [ url(r'sessions', SessionViewSet.as_view()), url(r'^docs/', schema_view), ] urlpatterns += router.urls
-
Daniel Roseman about 6 yearsI don't understand what you mean. That tutorial creates both viewsets and a standalone APIView; you seem to be mixing up the two methods.
-
alexca about 6 yearsYes, that tutorial creates both viewsets and a standalone APIView, I've created just a APIView to have a custom view and have just the GET endpoint instead of the CRUD, and that's working in my laptop, I mean, if I run the project on my laptop it works right, but I'm trying to run the same project on my raspberry pi and I'm getting that error. I've just tried to change the APIView to a ViewSet on the Raspberry Pi and it works, but I want to use an APIView to have an endpoint with just the GET endpoint.
-
Daniel Roseman about 6 yearsYou need to show your urls.py; as you can see from the tutorial, viewsets and standalone views are referenced differently in the urls.
-
alexca about 6 yearsThank you Daniel, I just edited my question and I've added my urls.py
-
Daniel Roseman about 6 yearsYou're registering that view twice. You don't need a router for a standalone view. (Note, you really shouldn't call it a viewset in the first place if it is not one.)
-
alexca about 6 yearsThank you Daniel!! I was reading a bit more about APIView once you said that I don't need a router for a standalone view and I modified my urls.py using format_suffix_patterns instead of routes and It works now! thank you!
-
pass-by-ref over 5 yearsThe most important statement in the explanation is - You don't need a router for a standalone view. This statement solved all my problems. Thanks.
-
Oleg Belousov over 4 yearsHi! I am using DRF 3.10.2 with Django 2.2.4. Adding this stub method results in the router ignoring this route :(
-
MartinP about 4 yearstypo, viewsets.ViewSet
-
rmcsharry about 4 yearsAs of Apr 2020, this is the up-to-date answer. Thank you!
-
Thusjanthan Kubendranathan about 3 yearsIf you look at the DRF viewsets.py, it does extend from APIView and ViewSetMixin, the latter implements the get_extra_actions and so if you extend from viewsets.ViewSet, that should be good.