我有以下代码:
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提供,goodforms由https://github.com/carljm/django-form-utils提供。
问题是,FileFormMixin
的{{1}}永远不会被调用。我该如何解决这个问题?我真的需要他们所有人。现在它只执行__init__
和FilterForm
构造函数。
更新
所以,我查看了所有提到的类NewEntityForm
,并且他们正在调用super()!
__init__
:
FileFormMixin
class FileFormMixin(object):
def __init__(self, *args, **kwargs):
super(FileFormMixin, self).__init__(*args, **kwargs)
:
BetterForm
更多的是,打印类'mro为@ elwin-arens提出,给出以下输出:
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__
但FileFormMixin的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__
只有在我明确地将其称为@ tom-karzes建议时才会执行
答案 0 :(得分:4)
据推测,BetterForm并没有打电话给超级,因此连锁店停在那里。
你唯一能做的就是在声明中交换类的顺序:
class NewEntityForm(FileFormMixin, FilterForm):
当然,这可能会影响两个类中定义的任何其他方法。
答案 1 :(得分:4)
<强> TL;博士强>
在您发布的NewEntityForm
MRO中,您会看到课程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()
这会导致在调用__init__()
后未调用A super(C, self).__init__()
。
这就引出了NewEntityForm
的MRO看起来像什么的问题。您可以像这样打印mro:
print('NewEntityForm.__mro__', NewEntityForm.__mro__)
这可能会显示一个列表,其中FileFormMixin
来自一个不称之为超级初始化方法的类,正如丹尼尔罗斯曼已经说过的那样。
一种可能的解决方案可能是显式调用要应用的类的init,如下所示:
class NewEntityForm(FilterForm):
def __init__(self, *args, **kwargs):
super(NewEntityForm, self).__init__(*args, **kwargs)
FileFormMixin.__init__(self)
print('newentityform __init__')
或者你可以翻转NewEntityForm
的基类。
答案 2 :(得分: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)