Search code examples
pythondjangodjango-viewsdjango-querysetdjango-class-based-views

Django: Unable to Apply Function View Decorator to Class Based View


I'm migrating from regular function based views, to class based views. One of the things that I couldn't migrate were the decorators I used. The decorator in question checks if the credentials of the current user are valid and then executes the decorated function:

def custom_auth(function):

    @wraps(function)
    def wrap(request, *args, **kwargs):
        
        # Logic for validating if user has correct credentials

        # Fetches the user that accessed the function
        user_object = User.objects.get(username=request_username)       
        
        # Try to execute the decorated function. If it fails, redirect
        # to previous page and show an error popup   
        try:
            return function(request, user=user_object, *args, **kwargs)
        except:
            # Logic for displaying the popup

Previously I could just decorate my function by doing

@custom_auth
def view(request, *args, **kwargs):
    # View logic

However, when I try to apply it to my class based view in the same way, I get an error saying __init__() takes 1 positional argument but 2 were given: user='username', view='cbvview'

@custom_auth
class CBV(View):

    def get(self, request, *args, **kwargs):
        # Get request logic 

I know that this is not the way you are supposed to apply the decorator, so I tried with different approaches. Either adding the decorator to urls.py, adding the @method_decorator(custom_auth, name="dispatch") or simply overriding the dispatch method, but none of them work. All of them give me the same error.

What could be the issue? Maybe I should use a custom mixin instead?


Solution

  • Use @method_decorator like following:

    from django.utils.decorators import method_decorator
    
    @method_decorator(custom_auth,name="dispatch")
    class CBV(View):
        
      def get(self, request, *args, **kwargs):
          ...
    

    Edit:

    Try to make your own mixin as class and inherit it to be used in CBV class so:

    class CustomAuthMixin:
        def dispatch(self, request, *args, **kwargs):
            # Logic for validating if user has correct credentials
    
            # Fetches the user that accessed the function
            user_instance = User.objects.get(username=request_username)       
            
            # Try to execute the decorated function. If it fails, redirect
            # to previous page and show an error popup   
            try:
                return super().dispatch(request, user=user_instance, *args, **kwargs)
            except:
                # Logic for displaying the popup
    
    class CBV(CustomAuthMixin, View):
    
        def get(self, request, *args, **kwargs):
            # Get request logic