首页 > 解决方案 > Django如何扩展通用视图类

问题描述

我注意到我正在为我网站上的许多视图设置站点范围的上下文变量和请求变量。自然,这种情况需要继承。如果我所有的基于视图类的视图都继承自 SiteView 而不是通用视图,我可以将所有共性分解到 SiteView 子类中。然后我可以从 SiteView 继承我所有的视图。但是,我不能让它工作。这是我的代码:

from django.contrib.auth.decorators import login_required
from django.views.generic import View
from django.utils.decorators import method_decorator

class SiteView(View):
    ''' Extends the generic django-supplied View class '''

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
         return super(SiteView, self).dispatch(*args, **kwargs)

    def get(self, *args, **kwargs):
        ''' Adds the variables required in the get request '''
        context = super(SiteView, self).get(*args, **kwargs)

        context['common_var'] = 'some common value'
        context['user'] = request.user

        return self.render_to_response(context)

这会引发以下类型错误:

    dispatch() missing 1 required positional argument: 'request'

任何帮助,将不胜感激

编辑:即使标记了正确答案,代码也存在其他问题。特别是,SiteView 的 get 方法不应该有以下行:

context = super(SiteView, self).get(*args, **kwargs)

这是因为 View 类没有任何 get 方法。

标签: djangodjango-views

解决方案


您忘记将请求传递给super().dispatch(..)调用:

class SiteView(View):

    @method_decorator(login_required)
    def dispatch(self, request, *args, **kwargs):
         return super(SiteView, self).dispatch(request, *args, **kwargs)

或者你可以省略参数request中的dispatch,从而通过*argsand传递它**kwargs

class SiteView(View):

    @method_decorator(login_required)
    def dispatch(self, *args, **kwargs):
         return super(SiteView, self).dispatch(*args, **kwargs)

然而,传递函数的名称可能更优雅,例如:

@method_decorator(login_required, name='dispatch')
class SiteView(View):

    # ...

编辑:请注意 aView没有get(..),post(..)等方法。该dispatch(..)方法将查看是否存在此类方法,如果存在则重定向到它。如果这样的方法不存在,它将返回“405 Method Not Allowed”响应。

因此,您的get(..)功能可以像这样实现:

@method_decorator(login_required, name='dispatch')
class SiteView(View):
    ''' Extends the generic django-supplied View class '''

    def render_to_response(self, context):
        # ...

    def get(self, request, *args, **kwargs):
        context = {
            'common_var': 'some common value',
            'user': request.user
        }
        return self.render_to_response(context)

实现“mixin”可能更有意义(也许使用LoginRequiredMixinmixin [Django-doc]的子类。

例如像:

class SiteViewMixin(LoginRequiredMixin):

    def get_context_data(self, *args, **kwargs):
        context = super().get_context_data(*args, **kwargs)
        context.update(common_var='some common value', user=self.request.user)
        return context

然后在另一个视图中使用 mixin,例如:

class SomeView(SiteViewMixin, TemplateView):
    # ...

推荐阅读