2016-06-12 2 views
4

У меня есть следующий код:не __init__ вызывается для двойного унаследованного класса

from form_utils import forms as betterforms 
from django.db import models 

class FilterForm(betterforms.BetterForm): 
    def __init__(self, *args, **kwargs): 
     super(FilterForm, self).__init__(*args, **kwargs) 
     print('filter form __init__') 

    ... 

class NewEntityForm(FilterForm, FileFormMixin): 
    def __init__(self, *args, **kwargs): 
     super(NewEntityForm, self).__init__(*args, **kwargs) 
     # super(FileFormMixin, self).__init__() <-- really does not matter 
     print('newentityform __init__') 

FileForMixin определяется следующим образом:

class FileFormMixin(object): 
    def __init__(self, *args, **kwargs): 
     super(FileFormMixin, self).__init__(*args, **kwargs) 
     print('file form mixin __init__') 

FileFormMixin предоставленный https://github.com/mbraak/django-file-form, betterforms по https://github.com/carljm/django-form-utils.

Проблема в том, что FileFormMixin__init__ никогда не набирается. Как я могу это исправить? Мне действительно все они нужны. Сейчас он исполняет только FilterForm и NewEntityForm конструкторы.

UPDATE

Итак, я смотрел на все упомянутые классы __init__ «с, и они называют супер()!

FileFormMixin:

class FileFormMixin(object): 
    def __init__(self, *args, **kwargs): 
     super(FileFormMixin, self).__init__(*args, **kwargs) 

BetterForm:

class BetterBaseForm(object): 
    ... 
     def __init__(self, *args, **kwargs): 
     self._fieldsets = deepcopy(self.base_fieldsets) 
     self._row_attrs = deepcopy(self.base_row_attrs) 
     self._fieldset_collection = None 
     super(BetterBaseForm, self).__init__(*args, **kwargs) 

class BetterForm(with_metaclass(BetterFormMetaclass, BetterBaseForm), 
       forms.Form): 
    __doc__ = BetterBaseForm.__doc__ 

Более того, печать класса MRO, как @ предложил Элвин-Аренса, дает следующий результат:

filter form __init__ NewEntityForm.__mro__ (<class 'myapp.forms.NewEntityForm'>, <class 'myapp.forms.FilterForm'>, <class 'form_utils.forms.BetterForm'>, <class 'django.forms.widgets.NewBase'>, <class 'form_utils.forms.BetterBaseForm'>, <class 'django.forms.forms.Form'>, <class 'django.forms.forms.BaseForm'>, <class 'django_file_form.forms.FileFormMixin'>, <class 'object'>) newsiteform __init__

Но __init__ для FileFormMixin выполняется только в том случае, если я называю это явно как @ tom-karzes advised

ответ

3

Предположительно, BetterForm не называет super, поэтому цепочка останавливается там.

Единственное, что вы можете сделать, это поменять порядок классов в объявлении:

class NewEntityForm(FileFormMixin, FilterForm): 

Хотя, конечно, это может повлиять на какие-либо другие методы, которые определены в обоих классах.

+0

Может быть, добавьте, почему замена заказа на изменение MRO без изменения - как указано, это может вызвать другие проблемы. Я понимаю, это потому, что модуль betterforms, не вызывающий супер-метод в смешанном инициализаторе класса, не должен быть переменным (третий сторонний код), правильно? – Dilettant

+0

, пожалуйста, ознакомьтесь с обновленным вопросом – user37741

+0

подкачки классов заказа решили проблему. благодаря! – user37741

0

Вы можете обращаться к родительским классам явно при вызове их методов __init__. Например:

class Foo(object): 
    def __init__(self, x): 
     self.x = x 

class Bar(object): 
    def __init__(self, y): 
     self.y = y 

class Baz(Foo, Bar): 
    def __init__(self, x, y): 
     Foo.__init__(self, x) 
     Bar.__init__(self, y) 
+0

см. Обновленный вопрос – user37741

3

Tl; дг

От Опубликованная МРО NewEntityForm вы видите класс BaseForm. In the source of django.forms.forms.BaseForm вы также можете видеть, что этот класс не вызывает super(BaseForm, self).__init__() и поэтому отвечает за разрыв цепочки с FileFormMixin.

В этом случае вы можете обойти эту проблему путем изменения порядка базовых классов NewEntityForm как так:

class NewEntityForm(FileFormMixin, FilterForm): 
    def __init__(self, *args, **kwargs): 
     super(NewEntityForm, self).__init__(*args, **kwargs) 

Объяснение

То, что вы, вероятно, думаете, что классы FilterForm и FileFormMixin существует как базовые классы бок о бок.

В действительности, наследуя от нескольких классов, создается порядок разрешения метода (MRO), который представляет собой список классов, проходящих по линейному порядку. Этот порядок определяет, что означает super в данном контексте.

Упрощенный пример, чтобы продемонстрировать:

class A(object): 
    def __init__(self): 
    super(A, self).__init__() 
    print('A', A.__mro__) 

class B(object): 
    def __init__(self): 
    super(B, self).__init__() 
    print('B', B.__mro__) 

class C(B, A): 
    def __init__(self): 
    super(C, self).__init__() 
    print('C', C.__mro__) 


c = C() 

super принимает класс и перемещает один направо в порядке разрешения методов. Итак, super(C, self).__init__() звонит B.__init__, что должно быть очевидно, но super(B, self).__init__() в этом контексте вызывает A.__init__, а не object.__init__, что, вероятно, менее очевидно.

Это происходит потому, что в приведенном выше примере кода C имеет следующий method resolution order:

C (<class 'C'>, <class 'B'>, <class 'A'>, <class 'object'>) 

Выражаясь в картинках, слева, если то, что вы могли бы ожидать, право это то, что на самом деле происходит:

Mental model    Actual model 
     C      C 
     |      | 
    /\      B 
     B A      | 
     | |      A 
     \/      | 
     object     object 

Так что, если B не называет это супер:

class A(object): 
    def __init__(self): 
    super(A, self).__init__() 
    print('A') 

class B(object): 
    def __init__(self): 
    print('B') 

class C(B, A): 
    def __init__(self): 
    super(C, self).__init__() 
    print('C') 


c = C() 

Это приводит к тому, что A __init__() не вызывается после вызова super(C, self).__init__().

В этом случае возникает вопрос, что выглядит MRO от NewEntityForm. Вы можете распечатать MRO следующим образом:

print('NewEntityForm.__mro__', NewEntityForm.__mro__) 

Это, вероятно, покажет список, где FileFormMixin приходит после того, как класс, который не называем это супер инициализации метод, как Даниэль Роземан уже сказал.

Возможное решение может быть явно вызывать инициализации класса вы хотите применить как так:

class NewEntityForm(FilterForm): 
    def __init__(self, *args, **kwargs): 
     super(NewEntityForm, self).__init__(*args, **kwargs) 
     FileFormMixin.__init__(self) 
     print('newentityform __init__') 

Или вы могли бы перевернуть базовые классы NewEntityForm вокруг.

+0

см. Обновленный вопрос – user37741

+0

'BaseForm' не называется супер. Супер в BaseForm для добавленного вами MRO должен запускать FileFormMixin '__init__'. Но если какой-либо из классов __before__ FileFormMixin не вызывает super init, цепь прерывается. https: // GitHub.ком/Джанго/Джанго/BLOB/ec6121693f112ae33b653b4364e812722d2eb567/Джанго/формы/forms.py # L72-98 –

Смежные вопросы