gos1
gos1

Reputation: 360

Using super() from outside a class in Django (or alternative to it, if any)

For the following I am using Python 2.7 / Django 1.5.

I am trying to refactor some production code which overrides Django form's clean() method with a custom validation procedure. It is repeated in several of the forms so we want to abstract it to an external function that we can just call within the forms.

Say I have the following,

# ... imports ...

class MyProperties(models.Model):
    label = models.CharField(max_length=100, blank=True, null=True, verbose_name=u'label'

    def __unicode__(self):
        return self.label

class MyForm(forms.ModelForm):
    choices = forms.ModelChoiceField(required=False, ...)

    class Meta:
        model = MyProperties

    def __init__(self, *args, **kwargs):
        super(MyForm, self).__init__(*args, **kwargs)

    def clean(self):
        return my_custom_clean_function(self)

def my_custom_clean_function(form_instance):
    cleaned_data = super(type(form_instance), form_instance).clean() ## DOES NOT WORK

    # other validation routines
    return cleaned_data

Calling super from the my_custom_clean_function from outside the class leads to exceeding the maximum recursive depth (is just calls the clean() method in the form_instance class, which calls the custom function, etc...

Creating a temp instance of ModelForm and calling it's clean method does not seem to work, since it would have none of the fields.

Is there any way to do this idiomatically, or would I be better off calling the parent clean method() from inside the form class, and then passing that data to my custom method for further validation?

Upvotes: 4

Views: 3535

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1122222

Your super(type(instance), instance).clean() works too; unless you are subclassing your forms further, at which point type(instance) would be the wrong object to pass in.

Alternatively use super() in the method and pass that result in:

class MyForm(forms.ModelForm):
    # ...

    def clean(self):
        return my_custom_clean_function(super(MyForm, form_instance).clean())

def my_custom_clean_function(cleaned_data):    
    # other validation routines
    return cleaned_data

Or you could just make it a mixin:

class SharedCleanupMixin:
    def clean(self):
        cleaned_data = super(SharedCleanupMixin, self).clean()
        # other validation routines
        return cleaned_data

and use that in your forms:

class MyForm(forms.ModelForm, SharedCleanupMixin):
    # ...

Upvotes: 4

Related Questions