user8802333
user8802333

Reputation: 489

How to have multiple of the same form on the same page in django

I am using the same form multiple times on my webpage.

This is my views.py

if request.method == "POST":
    form1 = TheForm(request.POST)
    form2 = TheForm(request.POST)
    form3 = TheForm(request.POST)

        if form1.is_valid() and form2.is_valid() and form3.is_valid():

This is my template page:

<form method="POST">
{% csrf_token %}
{{form1.as_p}}
{{form2.as_p}}
{{form3.as_p}}
<button class="waves-effect waves-light btn"> Button </button> </form>

When I try this however it only saves values from form3 not the others.

Thanks

Upvotes: 5

Views: 1916

Answers (3)

user8802333
user8802333

Reputation: 489

I found a solution, not sure if it's the most efficient one.

I just kept everything except now I shuffle the queryset in the template itself.

I used this link here in order to perform the shuffle, and I used this link troubleshoot the templatetags.

Upvotes: 0

JeanRibes
JeanRibes

Reputation: 131

having multiple times the same things in a <form> should work as described here.

For Django you need to use formsets, looks like what you want to achieve

Upvotes: 1

GwynBleidD
GwynBleidD

Reputation: 20569

The problem is caused by those 3 forms being absolutely identical, especially they have the same field names inside rendered HTML code. Let me show it by example.

Imagine your form being:

class TheForm(forms.Form):
    the_field = forms.CharField(label="Field")

After rendering your template, you will end up with pretty much this code:

<form method="POST">
    <input type="hidden" name="csrftoken" value="some-token">
    <p>
        <label for="id_the_field">Field</label>
        <input type="text" name="the_field" id="id_the_field">
    </p>
    <p>
        <label for="id_the_field">Field</label>
        <input type="text" name="the_field" id="id_the_field">
    </p>
    <p>
        <label for="id_the_field">Field</label>
        <input type="text" name="the_field" id="id_the_field">
    </p>
    <button class="waves-effect waves-light btn"> Button </button>
</form>

As you can see, all 3 forms have identical fields, including names of your input field. If this form will be submitted, there is no distinction between those fields, so all 3 forms on Django side will receive the same value (in your case it is from 3rd form, but that may vary on some circumstances).

To fix that, you can initialize each form with distinct prefix, as follows:

if request.method == "POST":
    form1 = TheForm(request.POST, prefix="form1")
    form2 = TheForm(request.POST, prefix="form2")
    form3 = TheForm(request.POST, prefix="form3")

    if form1.is_valid() and form2.is_valid() and form3.is_valid():
        form1.save()
        form2.save()
        form3.save()
        return HttpResponseRedirect(...)
    else:
        return render(....)
else:
    form1 = TheForm(prefix="form1")
    form2 = TheForm(prefix="form2")
    form3 = TheForm(prefix="form3")

Now, rendered HTML will look like:

<form method="POST">
    <input type="hidden" name="csrftoken" value="some-token">
    <p>
        <label for="id_form1_the_field">Field</label>
        <input type="text" name="form1_the_field" id="id_form1_the_field">
    </p>
    <p>
        <label for="id_form2_the_field">Field</label>
        <input type="text" name="form2_the_field" id="id_form2_the_field">
    </p>
    <p>
        <label for="id_form2_the_field">Field</label>
        <input type="text" name="form3_the_field" id="id_form3_the_field">
    </p>
    <button class="waves-effect waves-light btn"> Button </button>
</form>

As you can see, now fields have different, distinct names, so they will be sent separately by the browser back to your Django backend when user submits.

You can find out more on form prefixes in Django docs

Upvotes: 5

Related Questions