Difference between Django ModelForm and Model instance save methods
Asked Answered
C

2

5

I'm trying to understand the difference between Django's ModelForm save method and saving the Model instance directly.

Personally, I find saving directly more intuitive and more clearly shows when the data is saved. Plus, if I need to modify the instance before saving, then I have to use the Model save method as the Django documentation explains here.

So, once the form is validated, what is the difference? Would there be a difference if the form used multiple models or some other more complex use case?

I'm using Django version 1.4 if that matters. And below is some code showing how I tend to save validated form data.

Thanks in advance!

# models.py
class Project(models.Model):
    project_name = models.CharField(unique=True, null=False, blank=False)

# views.py
def add_project(request):
    if request.method == 'POST':
        project = Project()
        form = ProjectForm(request.POST, instance=project)

        if form.is_valid():
            project.save() ### <-- project.save() vs form.save() ###

            return HttpResponseRedirect(reverse('view_project', args=(project.id,)))
    else:
        form = ProjectForm()

    return render_to_response(
        'add_project.html',
        {
            'form': form,
        },
        context_instance=RequestContext(request)
    )

# forms.py
class ProjectForm(ModelForm):
    class Meta:
        model = Project
Comparison answered 6/1, 2013 at 18:3 Comment(0)
K
6

In the commented line you have, project.save() simply won't do anything. The instance has not been updated with the form data, it is simply the empty instance you created two lines before. The only way to update an existing instance is by saving its form.

Kappenne answered 6/1, 2013 at 18:50 Comment(6)
Hi Daniel, the project instance is updated in form = ProjectForm(request.POST, instance=project)Comparison
No, it isn't. It might be updated as a side-effect of the call to form.is_valid() (looking at the source, that calls ModelForm._post_save(), which in turn calls construct_instance()), but that does not do a full update and should not be relied upon. You should call form.save().Kappenne
+1 - don't rely on undocumented behaviour, you are asking for trouble later on.Dentalium
Hmm, if I print project.project_name before form.is_valid() the data entered by the user is printed. Debugging, the update seems to occur in BaseModelForm. However, testing multiple times I found one instance where this did not occur...though I've never seen it happen in production. I agree Blair, this is an accident waiting to happen.Comparison
Ok, testing a bit more, the project_name entered by they user is only printed when I have a breakpoint on the print statement. Otherwise, nothing is printed. Not sure why that is the case, but that's a different question. Thanks everyone!Comparison
@Comparison @Daniel I have encountered these exact 2 ridiculous situations myself, where: 1) The ModelForm constructor has the side-effect of mutating the model instance, and 2) This part of the code behaves differently when I step-in in the guts of Django with the PyCharm debugger. Most recent example here: link. I find the behaviour of the ModelForm constructor surprising, poorly-or-not-at-all documented and quite obnoxious, to be honest. But still, it would be easily debuggable, if it weren't for the debugger's gimmicks...Seasickness
N
2

ModelForm.save() returns an object saved from the data that was put into the form, Model.save() returns an object from the data that the object was initialized with or values that were set after it was created. So when it comes to getting the data from what the user inputted on the form to a persisted object, it makes more sense to call ModelForm.save() rather than going through the work of validating the data yourself, initializing the object and then saving it because all that work is handled by the ModelForm.

Nitz answered 6/1, 2013 at 21:33 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.