1👍
✅
Ok – I was able to figure out how this code should be restructured. For other newbies who are trying to make it so users can submit different forms for different models on the same page and not be bothered with the pesky resubmit on page refresh, here is the general structure to follow:
- Templates: put each model form in the template, but make sure the action attributes point to different views
- URLConfs: have correct url-mapping in your urls.py for each view in your forms’ action tags
- Views: create a total number of views equal to this equation: 1 + n. Where n = number of forms you want to process and the “1” refers to your actual page. Create a separate view for each form you put in the template. In each of these “n” views use all the standard stuff you see in the docs (i.e.
request.method == 'post'
andyourform.is_valid()
). But the key is that, you need to use theredirect('view:name')
after you process the form! I’m sure you could doredirect('/view/name/')
if you just want to hardcode the view in there. Using this redirect function, the system does not pass any data back to the main page view that it calls (the “1” from above.)
views.py
@login_required()
def index(request):
rhi_model_form = RhiModelForm()
activity_model_form = ActivityModelForm()
rhi_list = Rhi.objects.all()
activity_list = Activity.objects.all()
context = {
'rhi_model_form': rhi_model_form,
'rhi_list': rhi_list,
'activity_model_form': activity_model_form,
'activity_list': activity_list,
}
return render(request, 'ec/index.html', context)
@login_required()
def add_rhi(request):
if request.method == 'POST':
rForm = RhiModelForm(request.POST)
if rForm.is_valid():
rForm.save()
return redirect('ec:index')
else:
rhi_errors = rForm.errors
rhi_model_form = RhiModelForm()
context = {
'rhi_errors': rhi_errors,
'rhi_model_form': rhi_model_form,
}
return render(request, 'ec/index.html', context)
@login_required()
def add_activity(request):
if request.method == 'POST':
aForm = ActivityModelForm(request.POST)
if aForm.is_valid():
activity = aForm.save(commit=False)
activity.lastModifiedBy = request.user
activity.createdBy = request.user
activity.save()
return redirect('ec:index')
else:
activity_errors = aForm.errors
activity_model_form = ActivityModelForm()
context = {
'activity_errors': activity_errors,
'activity_model_form': activity_model_form,
}
return render(request, 'ec/index.html', context)
forms.py
class RhiModelForm(forms.ModelForm):
class Meta:
model = Rhi
exclude = ['slug']
class ActivityModelForm(forms.ModelForm):
class Meta:
model = Activity
exclude = ['createdBy','lastModifiedBy']
template (in my case – index.html)
{% if rhi_model_form %}
{% if error_message %}<p><strong>{{error_message}}</strong></p>{% endif %}
{% if rhi_errors %}{{ rhi_errors }} {% endif %}
<form action="{% url 'ec:add_rhi' %}" method="post">
{% csrf_token %}
{{ rhi_model_form }}
<input type="submit" value="Add RHI"/>
</form>
{% endif %}
{% if activity_model_form %}
{% if error_message %}<p><strong>{{error_message}}</strong></p>{% endif %}
{% if activity_errors %}{{ activity_errors }} {% endif %}
<form action="{% url 'ec:add_activity' %}" method="post">
{% csrf_token %}
{{ activity_model_form.non_field_errors }}
{{ activity_model_form }}
<input type="submit" value="Add Activity"/>
</form>
{% endif %}
Summary – the core concepts to keep in mind are:
- POST: do not use this method unless you want to change stuff on the server. Basically, don’t have any code in any view that contains, checks for, etc “POST” unless if that view will itself process data from the user. In this example, that is why you do not see anything about “POST” in the index view.
- Redirect/Render: these two shortcuts are key. Redirect will send the flow of code to the view referenced in its parameter and it won’t pass the context. In my case, that’s exactly what I want. Render does not take a view as a parameter and should be used to “ship-out” data, in this case to the template.
- Side Notes: in the template, I wrap each form in “if” controls because I do not want to show a lone “submit” button for a different form to the end user if there is a form submission error on the current form being submitted. (Since a form’s action calls a distinct view and since I reload the failed form if it didn’t pass validation in its view.)
Source:stackexchange.com