Opened 12 years ago

Closed 12 years ago

#17161 closed Bug (invalid)

Call super in BaseForm.__init__

Reported by: reames@… Owned by: nobody
Component: Forms Version: 1.3
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

Currently /django/forms/forms.py BaseForm.__init__ (as well as a fair number of other classes) does not call super().__init__. This makes it impossible to create form mixins.
Consider:

from django import forms

class FormMixin(object):
  def __init__(self, *args, **kwargs):
    super(FormMixin, self).__init__(*args, **kwargs)
    self.my_flag = true

class MyForm(forms.Form, FormMixin):
  field1 = forms.CharField()

class MyModelForm(forms.ModelForm, FormMixin):
  class Meta(object):
    model = SpamModel

Because of python's mro the init() in the mixin never gets called because BaseForm.__init__ does not call it.

Ideally, all classes in django that have an __init__() should also call super().__init__()

Change History (2)

comment:1 by David Foster, 12 years ago

Component: UncategorizedForms

I believe if you reorder the superclasses, adding the call to super() is not necessary. For example:

class MyForm(FormMixin, forms.Form):
  field1 = forms.CharField()

I would normally add a mixin in this order anyway since I normally have the mixin override the superclass instead of inserting a mixin to be called by the superclass.

comment:2 by Luke Plant, 12 years ago

Resolution: invalid
Status: newclosed

The suggested change would break very badly, since object.__init__ does not accept any parameters and you will get a TypeError.

Unfortunately, multiple inheritance is pretty badly broken in Python for __init__. See http://freshfoo.com/blog/object__init__takes_no_parameters

The preferred solution is to avoid implementing __init__ in your mixin class, and to avoid using super inside the __init__ of the class that inherits from object. If you do need to inherit two __init__ methods, use a subclass that overrides __init__ and explicitly calls each __init__, as per
http://www.artima.com/weblogs/viewpost.jsp?thread=281127

e.g.

class AwithB(A, B):
    def __init__(self, arg_for_A, arg_for_B):
        A.__init__(arg_for_A)
        B.__init__(arg_for_B)

Therefore, the current code is as good as its going to get.

Note: See TracTickets for help on using tickets.
Back to Top