Greg
Greg

Reputation: 1991

Saving Django Formsets

The following code successfully adds a new ToolCalibration to my database, however it does not save the SerialFormset or PartFormset. I've been staring at this code trying to figure it out for quite some time now, so any and all help would be greatly appreciated. Thanks!

Forms.py

from django.forms import ModelForm
from django.forms.models import inlineformset_factory
from tool_cal.models import ToolCalibration, SerialNumber, PartNumber

class ToolForm(ModelForm):
    class Meta:
        model = ToolCalibration

SerialFormSet = inlineformset_factory(ToolCalibration, SerialNumber, can_delete=True)
PartFormSet = inlineformset_factory(ToolCalibration, PartNumber, can_delete=True)

Views.py

class ToolCreate(CreateView):
model = ToolCalibration
template_name = "create.html"
form_class = ToolForm
success_url = '/toolcal/success'

def get(self, request, *args, **kwargs):
    """
    Handles GET requests and instantiates blank versions of the form
    and its inline formsets.
    """
    self.object = None
    form_class = self.get_form_class()
    form = self.get_form(form_class)
    serial_form = SerialFormSet(prefix='serial')
    part_form = PartFormSet(prefix='part')
    return self.render_to_response(
        self.get_context_data(form=form,
                              serial_form=serial_form,
                              part_form=part_form))

def post(self, request, *args, **kwargs):
    """
    Handles POST requests, instantiating a form instance and its inline
    formsets with the passed POST variables and then checking them for
    validity.
    """
    self.object = None
    form_class = self.get_form_class()
    form = self.get_form(form_class)
    serial_form = SerialFormSet(self.request.POST, prefix='serial')
    part_form = PartFormSet(self.request.POST, prefix='part')
    if (form.is_valid() and serial_form.is_valid() and
        part_form.is_valid()):
        return self.form_valid(form, serial_form, part_form)
    else:
        return self.form_invalid(form, serial_form, part_form)

def form_valid(self, form, serial_form, part_form):
    """
    Called if all forms are valid. Creates a ToolCalibration instance along with
    associated Serial and Parts and then redirects to a
    success page.
    """
    self.object = form.save()
    serial_form.instance = self.object
    serial_form.save()
    part_form.instance = self.object
    part_form.save()
    return HttpResponseRedirect(self.get_success_url())

def form_invalid(self, form, serial_form, part_form):
    """
    Called if a form is invalid. Re-renders the context data with the
    data-filled forms and errors.
    """
    return self.render_to_response(
        self.get_context_data(form=form,
                              serial_form=serial_form,
                              part_form=part_form))

Upvotes: 0

Views: 358

Answers (1)

Alex
Alex

Reputation: 8539

Have you considered using django-extra-views? It contains a quick and easy CBV for dealing with InlineFormSets.

In addition to an InlineFormSetView and GenericInlineFormSetView, they've also got a CreateWithInlinesView that seems to be just what you want. Relevant docs here.

Example:

from extra_views import InlineFormSet, CreateWithInlinesView, UpdateWithInlinesView,
from extra_views.generic import GenericInlineFormSet

from tool_cal.models import ToolCalibration, SerialNumber, PartNumber    


class SerialNumberInline(InlineFormSet):
    model = SerialNumber


class PartNumberInline(GenericInlineFormSet):
    model = PartNumber


class ToolCreateView(CreateWithInlinesView):
    model = ToolCalibration
    inlines = [SerialNumberInline, PartNumberInline]

    def get_success_url(self):
        return self.object.get_absolute_url()

Even if you don't want to use them, you could dig through the code and see how they handle it.

Upvotes: 1

Related Questions