Django-如何在基于类的视图方法中使用装饰器?

Jos*_*omo 6 python django rest model-view-controller

我正在使用django 1.8开发一个站点。这是视图之一的示例:

class ProfileView(View):
    template_name = 'index.html'

    # Return profile of any role (client/employee/admin)
    # Login required
    def get(self, request, *args, **kwargs):
        try:
            profile = Profile.objects.get(user=request.user)
            agency = None

            if request.user.is_employee():
                employee = EmployeeProfile.objects.get(profile=profile)
                agency = employee.agency

            if request.user.is_manager():
                agency = Agency.objects.get(manager=request.user)

        except (Profile.DoesNotExist, EmployeeProfile.DoesNotExist, Agency.DoesNotExist) as e:
            return HttpResponseRedirect('/404')

        return render(request, self.template_name, {"profile": profile, "agency": agency})

    # Client sign up
    # No decorator is needed
    def post(self, request):
        sign_up = SignUpForm(request.POST, request.FILES)

        response = json.loads(utils.create_user(sign_up,request.POST['avatar']))
        if response['profile'] is None:
            return JsonResponse({"code": 400, "response": response['message']})
        profile = serializers.deserialize("json", response['profile']).next().object

        group = Group.objects.get(name='clients')
        profile.user.groups.add(group)

        return HttpResponseRedirect('/')
Run Code Online (Sandbox Code Playgroud)

问题是,根据对控制器(视图)的请求类型,我可以使用不同的装饰器吗?

Mar*_*nte 14

有一个非常简单的解决方案来实现你想要的,它并不意味着装饰dispatch方法。你必须使用method_decorator你的方法(get/post)并将装饰器调用(不是装饰器本身)作为参数传递。

在您的情况下,它将是:

from django.utils.decorators import method_decorator

class ProfileView(View):
template_name = 'index.html'

    # Return profile of any role (client/employee/admin)
    @method_decorator(login_required())
    def get(self, request, *args, **kwargs):
        ...

    # Client sign up
    # No decorator is needed
    def post(self, request):
        ...
Run Code Online (Sandbox Code Playgroud)

注意login_required装饰器中的括号。

您可以传递任何面向函数的装饰器,甚至是自定义装饰器。例如:

def white_list_check():
    def decorator(func):
        def wrapper(request, *args, **kwargs):
            ip = request.META.get('REMOTE_ADDR', '0.0.0.0')
            if ip in WHITE_LIST:
                return func(request, *args, **kwargs)
            else:
                return HttpResponseForbidden()
        return wrapper
    return decorator
Run Code Online (Sandbox Code Playgroud)

然后,再次:

class YourView(View):

    @method_decorator(white_list_check())
    def get(self, request):
        ...
Run Code Online (Sandbox Code Playgroud)

  • 请注意,对于 Django 2.2(可能还有所有较新的版本),您不需要将装饰器调用传递给“method_decorator”,只需装饰器本身就可以了。 (3认同)

Tit*_*ter 8

从Django 1.9开始,根据doc,可以以以下方式应用装饰器:

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator

@method_decorator(login_required, name='dispatch')
class YourClassBasedView(TemplateView):
    ...
Run Code Online (Sandbox Code Playgroud)

name装饰方法的名称在哪里。

或装饰物少的情况:

from django.contrib.auth.decorators import login_required
from django.views.decorators.cache import never_cache
from django.utils.decorators import method_decorator

decorators = [never_cache, login_required]

@method_decorator(decorators, name='dispatch')
class YourClassBasedView(TemplateView):
    ...
Run Code Online (Sandbox Code Playgroud)


ozg*_*gur 5

您可以重写dispatch方法并根据请求类型调用不同的装饰器:

from django.utils.decorators import method_decorator

class ProfileView(View):
    ... 

    def dispatch(self, *args, **kwargs):
        dispatch_method = super(ProfileView, self).dispatch

        if self.request.method == 'GET':
            dispatch_method = method_decorator(my_get_decorator)(dispatch_method)
        elif self.request.method == 'POST':
            dispatch_method = method_decorator(my_post_decorator)(dispatch_method)

        return dispatch_method(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)


mic*_*mit 5

一些像 never_cache 这样的装饰器可以在 urls.py 中使用,而不是旧的方式:在 views.py 中

例如 never_cache 装饰器:

在旧样式的 views.py 中:

from django.views.decorators.cache import never_cache

@never_cache
def oldstyle_view(request):
    # and so on
Run Code Online (Sandbox Code Playgroud)

使用基于类的视图时,在 urls.py 中:

from django.views.decorators.cache import never_cache

urlpatterns = patterns('',
     (r'someurl/^$', never_cache(SomeClassBasedView.as_view())),
)
Run Code Online (Sandbox Code Playgroud)

编辑 2015 年 8 月 1 日

注意:这对于那些没有在 views.py 中定义完整视图的视图很方便,否则装饰器也可以应用于视图中的 depatch 方法。