I'm trying to implement three forms on the same page in Django. Each form has its own submit button as shown in my code. When I submit data on any one form, the data is saved but the other forms go blank upon the resulting refresh, and I get a validation error on the other forms if a field was required, for example.
My hunch is that the way Django handles the POST and subsequent page refresh is what's causing the problem, and it's trying to validate all forms regardless of which submit button I press. I thought mapping the button names as shown would prevent this but clearly not, and perhaps I'll have to handle each form individually with AJAX to solve this. However I'm not SURE that's the fix, and would love it if someone could shed light on what's really happening (i.e., explain what Django is trying to do upon submit) so I can better understand how to solve. Any help is extremely appreciated. Handling multiple forms in one view in Django is anything but straightforward.
Here's my code:
Views.py
def update_machine_view(request, brand_name_slug, mclass_slug, profile_slug):
machineentry = MachineEntry.objects.prefetch_related().select_related().get(profile_slug=profile_slug)
f_plate = PlateForm(request.POST or None, instance=machineentry.plate)
f_dimensions = DimensionsForm(request.POST or None, instance=machineentry.dimensions)
f_chassis = ChassisForm(request.POST or None, instance=machineentry.chassis)
if request.method == 'POST' and 'save_plate' in request.POST:
if f_plate.is_valid():
f_plate.save()
if request.method == 'POST' and 'save_dimensions' in request.POST:
if f_dimensions.is_valid():
f_dimensions.save()
if request.method == 'POST' and 'save_chassis' in request.POST:
if f_chassis.is_valid():
f_chassis.save()
context = {
'f_plate': f_plate,
'f_dimensions': f_dimensions,
'f_chassis': f_chassis,
'obj': machineentry,
}
return render(request, "machines/update_machine_form.html", context)
Template:
<form method="post">
{% csrf_token %}
{{ f_plate | crispy }}
<button type='submit' name='save_plate'>Save</button>
</form>
<form method="post">
{% csrf_token %}
{{ f_dimensions | crispy }}
<button type='submit' name='save_dimensions'>Save</button>
</form>
<form method="post">
{% csrf_token %}
{{ f_chassis | crispy }}
<button type='submit' name='save_chassis'>Save</button>
</form>
What I can understand is that you are passing request.POST with every form even the ones which aren't submitted. But in request.POST, you have the values for the form you submitted, not the other ones. Hence the error is showing field is required. I suggest you to do like this:
def update_machine_view(request, brand_name_slug, mclass_slug, profile_slug):
machineentry = MachineEntry.objects.select_related('plate', 'dimensions', 'chassis').get(profile_slug=profile_slug)
f_plate = PlateForm(instance=machineentry.plate)
f_dimensions = DimensionsForm(instance=machineentry.dimensions)
f_chassis = ChassisForm(instance=machineentry.chassis)
if request.method == 'POST':
if 'save_plate' in request.POST:
f_plate = PlateForm(request.POST, instance=machineentry.plate)
if f_plate.is_valid():
f_plate.save()
if 'save_dimensions' in request.POST:
f_dimensions = DimensionsForm(request.POST, instance=machineentry.dimensions)
if f_dimensions.is_valid():
f_dimensions.save()
if 'save_chassis' in request.POST:
f_chassis = ChassisForm(request.POST, instance=machineentry.chassis)
if f_chassis.is_valid():
f_chassis.save()
context = {
'f_plate': f_plate,
'f_dimensions': f_dimensions,
'f_chassis': f_chassis,
'obj': machineentry,
}
return render(request, "machines/update_machine_form.html", context)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With