Home > Software engineering >  Can't handle two modelforms in a single submit/view flow with a FK relation?
Can't handle two modelforms in a single submit/view flow with a FK relation?

Time:03-28

I have the below two models

# models.py

class Applicant(models.Model):
    """
    A table to store all applicants, relates 1-n to an offer
    """
    name = models.CharField(max_length=50)
    job = models.CharField(max_length=50)
    start = models.DateField(null=True, blank=True)

    def __str__(self):
        return f'{self.name} applying for {self.job} starting {self.start}'


class Offer(models.Model):
    """
    A table to store created offers
    """
    # Relations
    applicant = models.ForeignKey(Applicant, on_delete=models.CASCADE)

    # Self
    monthly_raise = models.FloatField()
    months = models.PositiveIntegerField(validators=[MinValueValidator(1), MaxValueValidator(60)])
    start_salary = models.FloatField()

In my template I render all fields except for start (which I don't render at all) in the same <form></form> wrapper. Now in my view I want to create new instances for each of the modelforms but only if both are valid.

This is what I have which throws

NOT NULL constraint failed: planner_offer.applicant_id

def render_dashboard_planner(request):

    site = 'planner'

    if request.method == 'GET':
        applicant_form = ApplicantForm()
        offer_form = OfferForm()

        context = {
            'applicant_form': applicant_form,
            'offer_form': offer_form,
            'site': site
        }

        return render(request, "dashboard/dashboard_planner.html", context)

    else:
        # Process the created Offer
        applicant_form = ApplicantForm()
        offer_form = OfferForm()

        form_applicant = ApplicantForm(request.POST)
        form_offer = OfferForm(request.POST)

        if form_applicant.is_valid() and form_offer.is_valid():

            # Grab the data
            form_applicant.save(commit=True)

            # Create Offer instance
            form_offer.save(commit=False)
            form_offer.applicant = form_applicant
            form_offer.save(commit=True)

        context = {
            'site': site,
            'offer_form': offer_form,
            'applicant_form': applicant_form,
        }

        return render(request, "dashboard/dashboard_planner.html", context)

How would I fix the relation issue and is this a proper way to handle the workflow in that manner at all?

CodePudding user response:

You should set the .applicant on the .instance of the form, and use the instance of the form_applicant, not the form_applicant itself, so:

from django.shortcuts import redirect

def render_dashboard_planner(request):
    site = 'planner'
    if request.method == 'POST':
        form_applicant = ApplicantForm(request.POST, request.FILES)
        form_offer = OfferForm(request.POST, request.FILES)
        if form_applicant.is_valid() and form_offer.is_valid():

            # Grab the data
            applicant = form_applicant.save()
            form_offer.instance.applicant = applicant
            form_offer.save()
            return redirect('name-of-some-view')
    else:
        applicant_form = ApplicantForm()
        offer_form = OfferForm()

    context = {
        'applicant_form': applicant_form,
        'offer_form': offer_form,
        'site': site
    }
    return render(request, 'dashboard/dashboard_planner.html', context)
  • Related