Функция переопределения множественного наследования Python и ListView в django
Я создал класс подклассы ListView
и два пользовательских микса, которые внедрили функцию get_context_data
. Я хотел переопределить эту функцию в дочернем классе:
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
?
Ответы
Ответ 1
Это старый вопрос, но я верю, что ответ неверен. В вашем коде есть ошибка. Он должен гласить:
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
, а не суперклассы.
UPDATE
Я пропустил, что ваши микшины не называют супер. Им следует. Да, даже если они наследуют объект, потому что супер вызывает следующий метод в MRO, не обязательно родительский класс, в котором он находится.
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)
Для MyListView
MRO:
- MyListView
- ListSortedMixin
- ListPaginatedMixin
- ListView
- Что бы ни было выше ListView
...
п. Объект
Вызов их один за другим может работать, но не так, как он должен был использоваться.
ОБНОВЛЕНИЕ 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')
Ответ 2
Если то, что вы пытаетесь сделать, это вызов переписанных методов в фиксированном порядке. Используйте этот синтаксис:
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(type[, object])
:
Возвращает прокси-объект, который делегирует вызовы методов родителям или родственный класс типа. Это полезно для доступа к унаследованным методам, которые были переопределены в классе. Порядок поиска такой же, как и для getattr(), за исключением того, что сам тип пропускается.
Существует два типичных варианта использования для супер. В иерархии классов с одно наследование, супер может использоваться для обозначения родительских классов не называя их явно, тем самым делая код более ремонтопригодны. Это использование тесно связано с использованием супер в других языков программирования.
Второй вариант использования - поддерживать совместное множественное наследование в динамическая среда исполнения. Этот вариант использования уникален для Python и не найден в статически скомпилированных языках или языках, которые только поддержка одиночного наследования. Это позволяет реализовать "диаграммы алмаза", где несколько базовых классов реализуют одинаковые метод. Хороший дизайн диктует, что этот метод имеет тот же вызов подписи в каждом случае (поскольку порядок вызовов определяется в runtime, потому что этот порядок адаптируется к изменениям в иерархии классов, и потому что этот порядок может включать в себя родные классы, которые неизвестны до запуска).
Итак, аргумент super - это класс, для которого вы хотите получить прокси-сервер родительского или родственного класса. super(ListSortedMixin,self).get_context_data(**context)
не обязательно вызовет get_context_data
of ListSortedMixin
. Это зависит от порядка разрешения метода (MRO), который вы можете использовать с помощью print MyListView.__mro__
Итак, super()
вызовет get_context_data
родительского или родственного брата. Порядок выполнения адаптируется к изменениям в иерархии классов и потому, что этот порядок может включать в себя классы-братья, неизвестные до выполнения.