'Can't handle two modelforms in a single submit/view flow with a FK relation?
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?
Solution 1:[1]
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)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Willem Van Onsem |
