I'm working on an app for construction company, and I want to create form for our daily schedule. For this I have 4 models: Date, DailySchedule, WorkersSchedule and MachinerySchedule. Each day we are working on several construction sites and we have 3-4 machines per CS and a few engaged workers on those sites.
I'm trying to use inlineformset_factory with 3 levels of nesting, but without success:
form (pick a date)
formset0 (choose construction site)
formset1 (choose employees)
formset2 (choose machinery)
date
construction_site_1
employee_1
employee_2
machine_1
machine_2
machine_3
construction_site_2
employee_1
employee_2
machine_1
machine_2
machine_3
construction_site_3
employee_1
employee_2
employee_3
machine_1
machine_2
...
models.py
class Date(models.Model):
datum = models.DateField(blank=True, null=True)
def __str__(self):
return str(self.date)
class DailySchedule(models.Model):
date = models.ForeignKey(Date, on_delete=models.CASCADE, blank=True, null=True)
construction_site = models.ForeignKey(ConstructionSite, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return str(self.date) + ' --- ' + str(self.construction_site)
class WorkersSchedule(models.Model):
daily_schedule = models.ForeignKey(DailySchedule, on_delete=models.CASCADE, blank=True, null=True)
employees = models.ForeignKey(Employees, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return str(self.daily_schedule) + ' --- ' + str(self.employees)
class MachinerySchedule(models.Model):
daily_schedule = models.ForeignKey(DailySchedule, on_delete=models.CASCADE, blank=True, null=True)
machinery = models.ForeignKey(Machinery, on_delete=models.CASCADE, blank=True, null=True)
def __str__(self):
return str(self.daily_schedule) + ' --- ' + str(self.machinery)
forms.py
class DateForm(ModelForm):
class Meta:
model = Date
fields = "__all__"
views.py
def daily_schedule_form(request):
date = Date()
ds = DailySchedule()
form = DateForm()
DailyScheduleFormSet = inlineformset_factory(Date, DailySchedule, fields=('__all__'), can_delete=False, extra=2)
WorkersScheduleFormSet= inlineformset_factory(DailySchedule, WorkersSchedule, fields=('__all__'), can_delete=False, extra=2)
MachineryScheduleFormSet= inlineformset_factory(DailySchedule, MachinerySchedule, fields=('__all__'), can_delete=False, extra=2)
if request.method == 'POST':
form = DateForm(request.POST)
formset0 = DailyScheduleFormSet(request.POST, instance=date, prefix="formset0")
formset1 = WorkersScheduleFormSet(request.POST, instance=ds, prefix="formset1")
formset2 = MachineryScheduleFormSet(request.POST, instance=ds, prefix='formset2')
if form.is_valid():
form_data= form.cleaned_data
data = form.save()
formset0 = DailyScheduleFormSet(request.POST, instance=data, prefix="formset0")
if formset0.is_valid():
for f in formset0:
date = f.cleaned_data["date"]
construction_site = f.cleaned_data["construction_site"]
date.save()
construction_site.save()
ds_new = DailySchedule(date = date, construction_site = construction_site)
ds_new.save()
formset1 = WorkersScheduleFormSet(request.POST, instance=ds_new, prefix="formset1")
formset2 = MachineryScheduleFormSet(request.POST, instance=ds_new, prefix='formset2')
if formset1.is_valid() and formset2.is_valid():
....
return HttpResponseRedirect('/machinery/daily_schedule/')
else:
formset0 = DailyScheduleFormSet(prefix="formset0")
formset1 = WorkersScheduleFormSet(prefix="formset1")
formset2 = MachineryScheduleFormSet(prefix='formset2')
return render(request,"machinery/daily_schedule_form.html",{'form':form,'formset0':formset0,'formset1':formset1, 'formset2': formset2})
template
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
{{ formset0.management_form }}
{% for x in formset0 %}
{{x}}
{{ formset1.as_p }}
{{ formset2.as_p }}
{% endfor %}
<button type="submit">Save</button>
</form>
I'm stuck with the 3rd level of nesting - probably something with prefixes, but my level of knowledge is limited.
Is there a better way to achieve this? Maybe using DRF combined with React/JS or something else?
Any help is welcomed.