Как написать декоратор для разрешения просмотра на основе класса на основе объекта из представления

прямо сейчас я использую это приложение для проверки разрешений: django-rules

Однако он не обновлялся уже более года, и нет декоратора для «новых» (начиная с django 1.3) представлений на основе классов. Я хотел бы иметь возможность использовать urls.py следующим образом:

url(r'^casos/(?P<pk>\d+)/editar/$', rules_permission_required('lawsuits.logical_check', raise_exception=True)(CaseUpdateView.as_view()), name='case_edit'),

Я не могу понять, как получить объект из представления на основе класса из декоратора. У вас есть идеи? Вот что у меня есть до сих пор:

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

Спасибо заранее!


person Clash    schedule 04.04.2012    source источник


Ответы (2)


Используйте method_decorator в методе dispatch(): 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)

Или вы можете украсить вывод метода класса as_view либо в конфигурации вашего URL-адреса (как описано в ссылке выше), либо путем сохранения экземпляра в переменной.

class ClassBasedView(View):
    def dispatch(self, *args, **kwargs):
        return super(ClassBasedView, self).dispatch(*args, **kwargs)
class_based_view = rules_permission_required(ClassBasedView.as_view())

Хотя я не совсем уверен, может ли последний пример вызвать проблемы с безопасностью потоков (зависит от того, как Django обрабатывает экземпляры). Лучший способ, вероятно, придерживаться method_decorator.

person Danilo Bargen    schedule 04.04.2012

В итоге я использовал декоратор класса

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
person Clash    schedule 11.04.2012
comment
Может кто-нибудь объяснить, почему переключение на представления на основе классов является улучшением, если оно слишком усложняет такие вещи. Кажется, это шаг в неправильном направлении, если вы спросите меня. - person fred; 10.01.2014