19

我创建了一个子类ListView和两个已实现get_context_data功能的自定义 mixin 的类。我想在子类上覆盖这个函数:

from django.views.generic import ListView

class ListSortedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListSortedMixin'
        return kwargs

class ListPaginatedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListPaginatedMixin'
        return kwargs

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
  def get_context_data(self, **context):
    super(ListSortedMixin,self).get_context_data(**context)
    super(ListPaginatedMixin,self).get_context_data(**context)
    return context

当我执行MyListView它时只打印"ListSortedMixin". 出于某种原因,python 正在ListSortedMixin.get_context_data代替MyListView.get_context_data. 为什么?

如果我将继承顺序更改为ListPaginatedMixin, ListSortedMixin, ListView,ListPaginatedMixin.get_context_data将被执行。

如何覆盖该get_context_data功能?

4

3 回答 3

24

这是一个老问题,但我相信答案是不正确的。您的代码中有错误。它应该是:

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
    def get_context_data(self, **context):
        super(MyListView,self).get_context_data(**context)
        return context

调用 的顺序get_context_data与 的声明中指定的顺序相同MyListView。注意 super 的参数是MyListView而不是超类。

更新

我错过了你的混入不叫超级。他们应该。是的,即使它们从对象继承,因为 super 调用 MRO 中的 next 方法,不一定是它所在类的父级。

from django.views.generic import ListView

class ListSortedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListSortedMixin'
        return super(ListSortedMixin,self).get_context_data(**context)

class ListPaginatedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListPaginatedMixin'
        return super(ListPaginatedMixin,self).get_context_data(**context)

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
    def get_context_data(self, **context):
        return super(MyListView,self).get_context_data(**context)

对于MyListViewMRO,则为:

  1. 我的列表视图
  2. ListSortedMixin
  3. 列表分页混合
  4. 列表显示
  5. ListView 上面的任何内容... n。目的

一个一个地调用它们可能会起作用,但这不是它的预期使用方式。

更新 2

复制并粘贴示例以证明我的观点。

class Parent(object):
    def get_context_data(self, **kwargs):
        print 'Parent'

class ListSortedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListSortedMixin'
        return super(ListSortedMixin,self).get_context_data(**kwargs)

class ListPaginatedMixin(object):
    def get_context_data(self, **kwargs):
        print 'ListPaginatedMixin'
        return super(ListPaginatedMixin,self).get_context_data(**kwargs)

class MyListView(ListSortedMixin, ListPaginatedMixin, Parent):
    def get_context_data(self, **kwargs):
        return super(MyListView,self).get_context_data(**kwargs)


m = MyListView()
m.get_context_data(l='l')
于 2013-07-21T14:11:08.377 回答
10

如果您要做的是按固定顺序调用覆盖的方法。使用此语法:

class MyListView(ListSortedMixin, ListPaginatedMixin, ListView):
  def get_context_data(self, **context):
    ListSortedMixin.get_context_data(self, **context)
    ListPaginatedMixin.get_context_data(self, **context)
    return context

在这种情况下,Super 将不起作用。请参阅手册super(type[, object])

返回一个代理对象,它将方法调用委托给 type 的父类或同级。这对于访问已在类中重写的继承方法很有用。搜索顺序与 getattr() 使用的相同,只是跳过了类型本身。

super 有两个典型的用例。在具有单继承的类层次结构中,可以使用 super 来引用父类而无需显式命名它们,从而使代码更易于维护。这种用法与在其他编程语言中使用 super 非常相似。

第二个用例是在动态执行环境中支持协作多重继承。这个用例是 Python 独有的,在静态编译的语言或仅支持单继承的语言中找不到。这使得实现多个基类实现相同方法的“菱形图”成为可能。良好的设计要求此方法在每种情况下都具有相同的调用签名(因为调用的顺序是在运行时确定的,因为该顺序会适应类层次结构的变化,并且因为该顺序可以包括在运行前未知的兄弟类)。

所以 super 的参数是你想要获取其父类或兄弟类代理的类。super(ListSortedMixin,self).get_context_data(**context)不一定会调用get_context_data. ListSortedMixin这取决于您可以使用的方法解析顺序 (MRO)print MyListView.__mro__

父母或兄弟姐妹的super()电话也是如此。get_context_data执行顺序适应类层次结构的变化,因为该顺序可以包括在运行之前未知的兄弟类。

于 2012-03-30T08:57:25.670 回答
0

我发现大多数 Python 新手并在这里寻找答案的人将使用 Python 3 而不是 2,所以这里有一个小的更新。

class Parent(object):
    def get_context_data(self, **kwargs):
        print('Parent')

class ListSortedMixin(object):
    def get_context_data(self, **kwargs):
        print('ListSortedMixin')
        return super().get_context_data(**kwargs)

class ListPaginatedMixin(object):
    def get_context_data(self, **kwargs):
        print('ListPaginatedMixin')
        return super().get_context_data(**kwargs)

class MyListView(ListSortedMixin, ListPaginatedMixin, Parent):
    def get_context_data(self, **kwargs):
        return super().get_context_data(**kwargs)


m = MyListView()
m.get_context_data(l='l')
于 2019-12-06T18:02:11.663 回答