[Fixed]-Django – form_valid() vs save()

11👍

If you save a form with commit=False, you must call the form’s save_m2m method to save the many-to-many data. See the docs for more info.

If you decide to use the form_valid method, I would change the following things:

  • update the instance returned by form.save() and save it, instead of calling form.save() again.
  • explicitly call form.save_m2m()
  • return a redirect response instead of calling super().form_valid() (which will save the form again)

Putting that together, you get:

def form_valid(self, form):
    product = form.save(commit=False)
    product.user =  self.request.user
    product.location.location = user.user_location
    product.save()
    form.save_m2m()
    return redirect('/success-url/')

1👍

About your problem with manytomany i guess is the order they do things… Form > Admin > Models, when you use form_valid is the first thing they do before check other things in chain, while using save is the last, maybe can be because or other things too…

The best way is always use form_valid instead of raw save

form_valid first check the Clean function if there is any native validations errors or custom validations and only then save your models

save just save it without validate then with your form with your validations

Example

from django import forms

class ContactForm(forms.Form):
    # Everything as before.
    ...

    def clean(self):
        cleaned_data = super().clean()
        cc_myself = cleaned_data.get("cc_myself")
        subject = cleaned_data.get("subject")

        if cc_myself and subject:
            # Only do something if both fields are valid so far.
            if "help" not in subject:
                raise forms.ValidationError(
                    "Did not send for 'help' in the subject despite "
                    "CC'ing yourself."
                )

Source: https://docs.djangoproject.com/en/2.0/ref/forms/validation/

Leave a comment