How to write a decorator for a class based view - object based resolution from view
right now i am using this app to check permissions: django-rules
However, it hasn't been updated in over a year and there is no decorator for "new" (since django 1.3) classes. I would like to be able to use on urls.py like this:
url(r'^casos/(?P<pk>\d+)/editar/$', rules_permission_required('lawsuits.logical_check', raise_exception=True)(CaseUpdateView.as_view()), name='case_edit'),
I can't figure out how to get an object from a class view from a decorator. Do you have any ideas? Here's what I have so far:
from django.utils.decorators import available_attrs
def rules_permission_required(perm, queryset=None, login_url=None, raise_exception=False):
def wrapper(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
def inner(request, *args, **kwargs):
#view_func is the class based view -> <function MyEditView at 0x94e54c4>
print view_func.get_object() # doesnt work
print view_func(request, *args, **kwargs).get_object() # doesnt work either
#any ideas?
if not request.user.has_perm(perm, obj=obj):
return redirect_to_login(request, login_url, raise_exception)
return view_func(request, *args, **kwargs)
return inner
return wrapper
Thank you very much in advance!
source to share
Use method_decorator
for dispatch () method: https://docs.djangoproject.com/en/dev/topics/class-based-views/#decorating-class-based-views
from django.utils.decorators import method_decorator
class ClassBasedView(View):
@method_decorator(rules_permission_required)
def dispatch(self, *args, **kwargs):
return super(ClassBasedView, self).dispatch(*args, **kwargs)
Or you can decorate the output of a class method as_view
, either in the url config (as described in the link above) or by storing the instance into a variable.
class ClassBasedView(View):
def dispatch(self, *args, **kwargs):
return super(ClassBasedView, self).dispatch(*args, **kwargs)
class_based_view = rules_permission_required(ClassBasedView.as_view())
Though I'm not entirely sure if the last example might cause thread safety issues (depends on how Django handles instances). Your best bet is probably to stick with it method_decorator
.
source to share
I ended up using the class decorator
def rules_permission_required(perm, queryset=None, login_url=None, raise_exception=False):
def wrapper(cls):
def view_wrapper(view_func):
@wraps(view_func, assigned=available_attrs(view_func))
def inner(self, request, *args, **kwargs):
# get object
obj = get_object_from_classbased_instance(
self, queryset, request, *args, **kwargs
)
# do anything you want
return inner
cls.dispatch = view_wrapper(cls.dispatch)
return cls
return wrapper
source to share