Mantis
Mantis

Reputation: 1387

Django: form_valid() takes exactly 2 arguments (3 given)

I have got a CreateView for emergency lighting tests done on sites. It gets the site from the url so the user does not need to enter it into the form. The CreateView Also has a emergency lighting device formset to attach multiple devices to the main test. When I hit submit on the form i get

form_valid() takes exactly 2 arguments (3 given)

models.py

class Site(models.Model):
    ....

class EmergencyLighting(models.Model):
    site = models.ForeignKey(Site)

class EmergencyLightingDevice(models.Model):
    emergency_lighting = models.ForeignKey(EmergencyLighting)

views.py

class FormsetMixin(object):
    object = None

    def get(self, request, *args, **kwargs):
        if getattr(self, 'is_update_view', False):
            self.object = self.get_object()
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        formset_class = self.get_formset_class()
        formset = self.get_formset(formset_class)
        return self.render_to_response(self.get_context_data(form=form, formset=formset))

    def post(self, request, *args, **kwargs):
        if getattr(self, 'is_update_view', False):
            self.object = self.get_object()
        form_class = self.get_form_class()
        form = self.get_form(form_class)
        formset_class = self.get_formset_class()
        formset = self.get_formset(formset_class)
        if form.is_valid() and formset.is_valid():
            return self.form_valid(form, formset)
        else:
            return self.form_invalid(form, formset)

    def get_formset_class(self):
        return self.formset_class

    def get_formset(self, formset_class):
        return formset_class(**self.get_formset_kwargs())

    def get_formset_kwargs(self):
        kwargs = {
            'instance': self.object
        }
        if self.request.method in ('POST', 'PUT'):
            kwargs.update({
                'data': self.request.POST,
                'files': self.request.FILES,
            })
        return kwargs

    def form_valid(self, form, formset):
        self.object = form.save()
        formset.instance = self.object
        formset.save()
        return redirect('/sites/list')

    def form_invalid(self, form, formset):
        return self.render_to_response(self.get_context_data(form=form, formset=formset))


class EmergencyLightingCreate(FormsetMixin, CreateView):
    template_name = 'emergency_lighting/emergencylighting_form.html'
    model = EmergencyLighting
    form_class = EmergencyLightingForm
    formset_class = EmergencyLightingFormSet

    def form_valid(self, form):
        emergency_lighting = form.save(commit=False)
        emergency_lighting.site_id = self.kwargs['site']

        return super(EmergencyLightingCreate, self).form_valid(form)

forms.py

class EmergencyLightingForm(forms.ModelForm):
    class Meta:
        model = EmergencyLighting
        exclude = ('creation', 'last_modified')


class EmergencyLightingDeviceForm(forms.ModelForm):
    class Meta:
        model = EmergencyLightingDevice
        exclude = ('creation', 'last_modified')

EmergencyLightingFormSet = inlineformset_factory(EmergencyLighting, EmergencyLightingDevice,
                                                 extra=0, min_num=1, exclude=('creation', 'last_modified'))

urls.py

url(r'^(?P<site>[0-9]+)/create/$', EmergencyLightingCreate.as_view(), name='emergency-lighting-create'),

Upvotes: 0

Views: 946

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599788

Like the error says, you're passing three arguments to form_valid; that's because you explicitly overrode post to send those three, and modified the signature of form_valid in FormsetMixin to accept them. However in EmergencyLightingCreate you've reverted to only accepting two arguments. You need to be consistent about how many arguments your methods accept when you're subclassing.

Upvotes: 1

Related Questions