Binding a form to a model instanceDjango’s newforms module provides the helper method ‘form_for_instance’. The method will return a Form similar to the one returned by form_for_model but the initial data will be populated by the instance’s data. The form will have a ‘save’ method which will save changes to the instance to the database (unless it is passed the commit=False argument) and will return the instance itself.

Sometimes, however, it is desirable to use fields different from the default. In order to bind a form to an instance one will have to provide __init__ and save methods.

The __init__ method should be defined as follows:

def __init__(self, data=None, auto_id='id_%s', prefix=None,
initial=None, instance=None):
  if instance is not None:
    self.instance = instance
    new_data = {}
    # Populate new_data using 'instance'
    # ...
    data = new_data
    self.instance = None
super(MyForm, self).__init__(data, auto_id, prefix, initial)

The __init__ method will save the original instance in self.instance and pass the data it contains to the superclass (most likely forms.Form). The bound form will be created with MyForm(instance=MyInstance). To use the form for creating new instances it can be created with MyForm(request.POST).

The save method will look similar to the following:
def save(self, commit=True):
  if self.instance is not None:
    instance = self.instance
    instance = InstanceModel()

# Construct the instance below using self.clean_data
# Using self.clean_data ensures everything is validated.
# ...

if commit:
return instance

It should be noted that one will not be able to save ManyToMany data without saving the instance first. If the model contains M2M fields then commit=False will not make any sense.


Your add+edit view should look something like the following:

def add_edit_model(request, id=None):
if id is not None:
instance = MyModel.objects.get(id=id)
InstanceForm = MyForm(instance=instance)
InstanceForm = MyForm()

if request.POST:
form = InstanceForm(request.POST)
if form.is_valid():
return HttpResponseRedirect(‘/whatever/url/’)

return render_to_response(‘template.html’, {‘form’: InstanceForm})

Django Newforms