enter code hereI am working on a Django project that involves using a ModelForm for a Driver model and an inlineformset_factory for a related DriverTrip model. The formset is supposed to dynamically add trip details in the frontend, and I’m encountering a persistent validation error when trying to submit the formset.
models.py:
from django.db import models
class Driver(models.Model):
staff_id = models.CharField(max_length=100, unique=True)
driver_name = models.CharField(max_length=255)
duty_card_no = models.CharField(max_length=100)
class DriverTrip(models.Model):
driver = models.ForeignKey(Driver, on_delete=models.CASCADE)
route_name = models.CharField(max_length=255)
trip_type = models.CharField(max_length=50)
pick_up_time = models.TimeField()
drop_off_time = models.TimeField()
shift_time = models.TimeField()
head_count = models.IntegerField()
forms.py:
from django import forms
from django.forms import inlineformset_factory
from .models import Driver, DriverTrip
class DriverForm(forms.ModelForm):
class Meta:
model = Driver
fields = ['staff_id', 'driver_name', 'duty_card_no']
DriverTripFormSet = inlineformset_factory(
Driver,
DriverTrip,
fields=('route_name', 'trip_type', 'pick_up_time', 'drop_off_time', 'shift_time', 'head_count'),
extra=1,
can_delete=True
)
views.py:
from django.shortcuts import render, redirect
from .forms import DriverForm, DriverTripFormSet
from .models import Driver
def enter_head_count(request):
if request.method == 'POST':
driver_form = DriverForm(request.POST)
trip_formset = DriverTripFormSet(request.POST)
if driver_form.is_valid() and trip_formset.is_valid():
driver, created = Driver.objects.get_or_create(
staff_id=driver_form.cleaned_data['staff_id'],
defaults={
'driver_name': driver_form.cleaned_data['driver_name'],
'duty_card_no': driver_form.cleaned_data['duty_card_no'],
}
)
if not created:
driver.driver_name = driver_form.cleaned_data['driver_name']
driver.duty_card_no = driver_form.cleaned_data['duty_card_no']
driver.save()
trip_formset.instance = driver
trip_formset.save()
return redirect('success')
else:
print("Driver Form Errors:", driver_form.errors)
print("Trip Formset Errors:", trip_formset.errors)
else:
driver_form = DriverForm()
trip_formset = DriverTripFormSet()
return render(request, 'duty/enter_head_count.html', {
'driver_form': driver_form,
'trip_formset': trip_formset,
})
Html:
<
form method="post" id="driver-trip-form">
{% csrf_token %}
{{ driver_form.as_p }}
{{ trip_formset.management_form }}
<div id="trip-entries">
{% for form in trip_formset %}
<div class="form-row trip-form-container">
<div class="form-group">
{{ form.route_name.label_tag }}
{{ form.route_name }}
</div>
<div class="form-group">
{{ form.trip_type.label_tag }}
{{ form.trip_type }}
</div>
<div class="form-group">
{{ form.pick_up_time.label_tag }}
{{ form.pick_up_time }}
</div>
<div class="form-group">
{{ form.drop_off_time.label_tag }}
{{ form.drop_off_time }}
</div>
<div class="form-group">
{{ form.shift_time.label_tag }}
{{ form.shift_time }}
</div>
<div class="form-group">
{{ form.head_count.label_tag }}
{{ form.head_count }}
</div>
</div>
{% endfor %}
</div>
<div id="button-container" class="button-container">
<div id="add-row" class="add-icon">+</div>
<button type="submit" class="btn btn-success" id="submit-button">Submit</button>
</div>
</form>
JavaScript:
// JavaScript for dynamically adding formset fields
$(document).ready(function() {
var tripCount = {{ trip_formset.total_form_count|default:0 }};
$('#add-row').click(function() {
var newRow = `
<div class="form-row trip-form-container">
<div class="form-group">
<label>Route Name</label>
<input type="text" name="drivertrip_set-${tripCount}-route_name" class="form-control" placeholder="Enter Route Name" required>
</div>
<div class="form-group">
<label>Type</label>
<select name="drivertrip_set-${tripCount}-trip_type" class="form-control" required>
<option value="inbound">Inbound</option>
<option value="outbound">Outbound</option>
</select>
</div>
<div class="form-group">
<label>Pick Up Time</label>
<input type="time" name="drivertrip_set-${tripCount}-pick_up_time" class="form-control" required>
</div>
<div class="form-group">
<label>Drop Off Time</label>
<input type="time" name="drivertrip_set-${tripCount}-drop_off_time" class="form-control" required>
</div>
<div class="form-group">
<label>Shift Time</label>
<input type="time" name="drivertrip_set-${tripCount}-shift_time" class="form-control" required>
</div>
<div class="form-group">
<label>Head Count</label>
<input type="number" name="drivertrip_set-${tripCount}-head_count" class="form-control" placeholder="Enter Head Count" required>
</div>
<div class="remove-trip-container">
<span class="remove-trip">Remove</span>
</div>
</div>`;
$('#trip-entries').append(newRow);
$('#id_drivertrip_set-TOTAL_FORMS').val(++tripCount);
});
$(document).on('click', '.remove-trip', function() {
$(this).closest('.trip-form-container').remove();
tripCount--;
$('#id_drivertrip_set-TOTAL_FORMS').val(tripCount);
});
});
Problem Description:
When I try to submit the form, I encounter the error:
Formset Errors: [{‘route_name’: [‘This field is required.’], ‘pick_up_time’: [‘This field is required.’], ‘drop_off_time’: [‘This field is required.’], ‘shift_time’: [‘This field is required.’], ‘head_count’: [‘This field is required.’], ‘trip_type’: [‘This field is required.’]}]
This error appears when using the formset to dynamically add multiple trips. If a user manually fills in all details without using the autocomplete feature, the validation passes.
The backend expects formset field names like drivertrip_set-0-route_name, but dynamically added fields are indexed based on tripCount, e.g., drivertrip_set-0-route_name, drivertrip_set-1-route_name, etc.
Any help would be greatly appreciated!.