RnRoger
RnRoger

Reputation: 690

Django: Using decorators on methods in a subclass to handle requests from urls.py

I used to have some massive files with decorated funtions called from urls.py. This wasn't sustainable so they were split into controllers, with logic somewhere else (not relevant for this question). The controllers are subclassed from a main Controller class to share frequent imports and other commonalities. I can't get the decorator functions to work now, the closest I've gotten are

AssertionError: The `request` argument must be an instance of `django.http.HttpRequest`, not `api.controllers.FooController.FooController`.

and

AttributeError: 'functools.partial' object has no attribute '__name__'

Neither using a get() with as_view() nor a custom method work, as seen below. I've tried @method_decorator(login_required) etc. with no success. My files (simplified) are below. Do not mind the method contents, this is just for demonstration.

api/urls.py:

from django.urls import path
from api.controllers.FooController import FooController
urlpatterns = [
    path("get_foo", FooController,as_view(), name="get_foo")
    path("get_bar", FooController.foo_bar, name="get_bar")
]

api/controllers/Controller.py:

from django.views import View
from rest_framework.authentication import SessionAuthentication, TokenAuthentication
from rest_framework.decorators import api_view, authentication_classes, permission_classes
from django.http import HttpResponse, JsonResponse, StreamingHttpResponse
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator

class Controller(View):
    def __init__(self):
        # Set some variables
    # define some methods

api/controllers/FooController.py:

from api.controllers.Controller import *

class FooController(Controller):
    method_decorator(api_view(["GET"]))
    method_decorator(login_required)
    method_decorator(authentication_classes((SessionAuthentication, TokenAuthentication,)))
    method_decorator(permission_classes((IsAuthenticated,)))
    def get(self, request):
        if request.user.is_authenticated:
            return HttpResponse(status=200)
        else:
            return HttpResponse(status=401)

    method_decorator(api_view(["GET"]))
    method_decorator(login_required)
    method_decorator(authentication_classes((SessionAuthentication, TokenAuthentication,)))
    method_decorator(permission_classes((IsAuthenticated,)))
    def foo_bar(self, request):
        if request.user.is_authenticated:
            return JsonResponse({"data": "some data"}, status=200)

Thanks so much in advance if anyone can help me with this!

Upvotes: 0

Views: 206

Answers (1)

Rogier Stegeman
Rogier Stegeman

Reputation: 28

In your urls.py, use paths like so:

path("get_foo", FooController.as_view({"get":"get_foo"}), name="get_foo"),

Use Django's APIView in your base Controller.py:

from rest_framework import viewsets
class Controller(viewsets.ViewSet):
    def __init__(self):
        # Code

Then start your FooController class in FooController.py like so:

class FooController(Controller):
    authentication_classes = [SessionAuthentication, TokenAuthentication]
    permission_classes = [IsAuthenticated]
    def get_foo(self, request):

Upvotes: 1

Related Questions