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)?
source to share
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):
...
source to share
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.
source to share
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)
source to share