Django: 无法将函数视图装饰器应用于基于类的视图

huangapple go评论67阅读模式
英文:

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

问题

我正在从常规函数视图迁移到基于类的视图。其中一件事我无法迁移的是我使用的装饰器。有一个装饰器检查当前用户的凭证是否有效,然后执行被装饰的函数:

def custom_auth(function):

    @wraps(function)
    def wrap(request, *args, **kwargs):
        
        # 用于验证用户是否具有正确凭证的逻辑

        # 获取访问该函数的用户
        user_object = User.objects.get(username=request_username)       
        
        # 尝试执行被装饰的函数。如果失败,重定向到上一页并显示错误弹窗   
        try:
            return function(request, user=user_object, *args, **kwargs)
        except:
            # 显示弹窗的逻辑

以前,我只需这样装饰我的函数:

@custom_auth
def view(request, *args, **kwargs):
    # 视图逻辑

然而,当我尝试以相同的方式应用到我的基于类的视图时,出现了一个错误,错误信息为__init__()接受1个位置参数,但给定了2个:user='username',view='cbvview'

@custom_auth
class CBV(View):

    def get(self, request, *args, **kwargs):
        # 获取请求逻辑 

我知道这不是应用装饰器的方式,所以我尝试了不同的方法。无论是将装饰器添加到urls.py中,添加@method_decorator(custom_auth, name="dispatch")或者简单地覆盖dispatch方法,但都无法正常工作。它们都给我同样的错误。

可能的问题是什么?也许我应该使用自定义混入(mixin)?

英文:

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?

答案1

得分: 1

来自Django文档的代码链接:https://docs.djangoproject.com/en/4.1/topics/class-based-views/intro/

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

无需在装饰器的函数调用中添加用户,它已经包含在请求中。

英文:

from django docs https://docs.djangoproject.com/en/4.1/topics/class-based-views/intro/

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

and there is no need to add the user to the function call in the decorator. It is already in the request

答案2

得分: 1

Use @method_decorator 如下所示:

from django.utils.decorators import method_decorator

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

编辑:

尝试创建自己的mixin类并继承它以在CBV类中使用,如下所示:

class CustomAuthMixin:
    def dispatch(self, request, *args, **kwargs):
        # 验证用户是否具有正确的凭据的逻辑

        # 获取访问函数的用户
        user_instance = User.objects.get(username=request_username)       
        
        # 尝试执行已装饰的函数。如果失败,重定向到上一页并显示错误弹出窗口   
        try:
            return super().dispatch(request, user=user_instance, *args, **kwargs)
        except:
            # 显示弹出窗口的逻辑

class CBV(CustomAuthMixin, View):

    def get(self, request, *args, **kwargs):
        # 获取请求的逻辑
英文:

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 

huangapple
  • 本文由 发表于 2023年2月7日 02:20:26
  • 转载请务必保留本文链接:https://go.coder-hub.com/75365158.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定