Johan Vergeer
Johan Vergeer

Reputation: 5568

Django save multiple modelforms in view

I am probably missing something very obvious here, but can't get this to work.

I have 2 models (Organization and Address), 2 forms (One for each model) and 1 view where I want to save the Organization with the Address as the child.

Models:

class Address(models.Model):
    address = models.CharField(max_length=255, verbose_name=_("Address"))
    postal_code = models.CharField(max_length=20, verbose_name=_("Postal_code"))
    city = models.CharField(max_length=255, verbose_name=_("City"))


class Organization(models.Model):
    name = models.CharField(max_length=100, verbose_name=_("Name"))
    address = models.OneToOneField(Address, on_delete=models.CASCADE, verbose_name=_("Address"))

    owner = models.ForeignKey("users.User", related_name="organizations", verbose_name=_("Owner"))

Forms:

class AddressForm(forms.ModelForm):
    class Meta:
        model = Address
        fields = ["address", "postal_code", "city"]

    def __init__(self, *args, **kwargs):
        super(AddressForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        self.helper.form_tag = False
        self.helper.disable_csrf = True


class OrganizationForm(forms.ModelForm):
    class Meta:
        model = Organization
        fields = ["name", ]

    def __init__(self, *args, **kwargs):
        super(OrganizationForm, self).__init__(*args, **kwargs)
        self.helper = FormHelper(self)
        self.helper.form_tag = False
        self.helper.disable_csrf = True

And finally the view

class OrganizationCreateView(LoginRequiredMixin, TemplateView):
    template_name = "organizations/organization_form.html"

    def get_organization_form(self, data=None):
        return OrganizationForm(data)

    def get_address_form(self, data=None):
        return AddressForm(data)

    def get(self, request, *args, **kwargs):
        ctx = self.get_context_data(organization_form=OrganizationForm(),
                                    address_form=AddressForm())
        return self.render_to_response(ctx)

    def post(self, request, *args, **kwargs):
        organization_form = self.get_organization_form(data=request.POST)
        address_form = self.get_address_form(data=request.POST)

        if organization_form.is_valid() and address_form.is_valid():
            return self.forms_valid(organization_form, address_form)
        return self.forms_invalid(organization_form, address_form)

    def forms_valid(self, organization_form, address_form):
        address = address_form
        address.country = "DE"
        address.save()

        organization = organization_form
        organization.save(commit=False)

        organization.owner = self.request.user
        organization.address = address
        organization.save()

        return redirect("list")

    def forms_invalid(self, organization_form, address_form):
        ctx = self.get_context_data(organization_form=self.get_organization_form(organization_form),
                                    address_form=self.get_address_form(address_form))
        return self.render_to_response(ctx)

So I do save the Address, next the Organization (with commit=False), add the Address to the organization, save the organization, and presto: an Exception

Exception Type: IntegrityError at /organizations/create/
Exception Value: null value in column "address_id" violates not-null constraint
DETAIL:  Failing row contains (9, slkdfjlsdfk, lkdjflskdjflsd, , llksjjdlfkjsdlfkjsldkfj, f, null, null, null, null, null, null, null, null, null, null).

As I already mentioned, it is probably something very obvious, but can't find it. Can someone help me out here?

Upvotes: 0

Views: 29

Answers (1)

Daniel Roseman
Daniel Roseman

Reputation: 599600

You're slightly confused about how to create a model instance from a form. The instance is returned from the call to form.save(); it's that instance to which you need to assign the address and user.

def forms_valid(self, organization_form, address_form):
    address = address_form.save(commit=False)
    address.country = "DE"
    address.save()

    organization = organization_form.save(commit=False)
    organization.owner = self.request.user
    organization.address = address
    organization.save()

    return redirect("list")

Upvotes: 2

Related Questions