Django - how to use decorator in class based view methods?

I am developing a site with django 1.8. This is an example of one of the views:

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('/')

      

The question is, can I have different decorators according to the type of request that is being made to the controller (view)?

+3


source to share


4 answers


You need to apply a decorator to the dispatcher method of the class. This can be done as follows:



class ProfileView(View):

    @youdecorator
    def dispatch(self,request,*args,**kwargs):
        return super(ProfileView,self).dispatch(request,*args,**kwargs)
    //Rest of your code.

      

+3


source


There is a very simple solution to achieve what you want and that doesn't mean decorating the method dispatch

. You must use method_decorator

on top of your methods (get / post) and pass a <decorative call (not the decorator itself) as a parameter.

In your case, it would be:

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):
        ...

      

Notice the paretesis in the decorator login_required

.



You can pass any functionally oriented decorator, even a custom one. For example:

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

      

And again, again:

class YourView(View):

    @method_decorator(white_list_check())
    def get(self, request):
        ...

      

+3


source


Some decorators like never_cache can be used in urls.py instead of the old way: in views.py

eg. never_cache decorator:

in old style views.py:

from django.views.decorators.cache import never_cache

@never_cache
def oldstyle_view(request):
    # and so on

      

when using class based views, in urls.py:

from django.views.decorators.cache import never_cache

urlpatterns = patterns('',
     (r'someurl/^$', never_cache(SomeClassBasedView.as_view())),
)

      

Edit 1st Aug 2015

Note. This can be handy for those views where you don't have the full view defined in views.py, otherwhise. The decorator can also be applied to the depilatory technique in the view.

+2


source


You can override the method dispatch

and call different decorators based on the request type:

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)

      

+1


source







All Articles