Django:一个基于类的视图,具有mixins和dispatch方法

ver*_*4ka 22 django mixins django-views

通常,我使用dispatch基于类的视图的方法来设置一些初始变量或根据用户的权限添加一些逻辑.

例如,

from django.views.generic import FormView
from braces.views import LoginRequiredMixin

class GenerateReportView(LoginRequiredMixin, FormView):
    template_name = 'reporting/reporting_form.html'
    form_class = ReportForm

    def get_form(self, form_class):
        form = form_class(**self.get_form_kwargs())
        if not self.request.user.is_superuser:
            form.fields['report_type'].choices = [
                choice for choice in form.fields['report_type'].choices
                if choice[0] != INVOICE_REPORT
            ]
        return form
Run Code Online (Sandbox Code Playgroud)

它按预期工作:当匿名用户访问页面时,调用LoginRequiredMixindispatch方法,然后将用户重定向到登录页面.

但是,如果我想为此视图添加一些权限或设置一些初始变量,例如,

class GenerateReportView(LoginRequiredMixin, FormView):

    def dispatch(self, *args, **kwargs):
        if not (
            self.request.user.is_superuser or
            self.request.user.is_manager
        ):
            raise Http404
        return super(GenerateReportView, self).dispatch(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

在某些情况下它不起作用,因为dispatch视图继承的mixins的方法尚未被调用.因此,例如,为了能够请求用户的权限,我必须重复以下验证LoginRequiredMixin:

class GenerateReportView(LoginRequiredMixin, FormView):

    def dispatch(self, *args, **kwargs):
        if self.request.user.is_authenticated() and not (
            self.request.user.is_superuser or
            self.request.user.is_manager
        ):
            raise Http404
        return super(GenerateReportView, self).dispatch(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

这个例子很简单,但有时在mixin中有一些更复杂的逻辑:它检查权限,进行一些计算并将其存储在类属性中等.

现在我通过从mixin复制一些代码来解决它(比如上面的例子)或者将dispatch视图方法中的代码复制到另一个mixin并在第一个之后继承它以按顺序执行它们(这不是那个)很漂亮,因为这个新的mixin只能用于一个视图).

有没有正确的方法来解决这些问题?

KeP*_*ePe 5

我会编写自定义类,检查所有权限

from django.views.generic import FormView
from braces.views import AccessMixin

class SuperOrManagerPermissionsMixin(AccessMixin):
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_authenticated():
            return self.handle_no_permission(request)
        if self.user_has_permissions(request):
            return super(SuperOrManagerPermissionsMixin, self).dispatch(
                request, *args, **kwargs)
        raise Http404 #or return self.handle_no_permission

    def user_has_permissions(self, request):
        return self.request.user.is_superuser or self.request.user.is_manager

# a bit simplyfied, but with the same redirect for anonymous and logged users
# without permissions


class SuperOrManagerPermissionsMixin(AccessMixin):
    def dispatch(self, request, *args, **kwargs):
        if self.user_has_permissions(request):
            return super(SuperOrManagerPermissionsMixin, self).dispatch(
                request, *args, **kwargs)
        else:
            return self.handle_no_permission(request)

    def user_has_permissions(self, request):
        return request.user.is_authenticated() and (self.request.user.is_superuser
                                                    or self.request.user.is_manager)


class GenerateReportView(SuperOrManagerPermissionsMixin, FormView):
#Remove next two lines, don't need it
    def dispatch(self, *args, **kwargs):
        #or put some logic here
        return super(GenerateReportView, self).dispatch(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

并且类GenerateReportView(SuperOrManagerPermissionsMixin,FormView)的实现不需要重写调度方法

如果您使用多重继承,并且其中一个父类需要进行一些改进,那么最好先进行改进。它使代码更整洁。