1

I know this question has been answered before on this site, but for the life of me I can't figure it out. I want to submit two forms at once, with one submit button. Please, can anybody identify what is wrong with my code, this is driving me insane.

HTML template (edited)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title></title>
</head>

<body>



<form action="{% url "list" %}" method="post" enctype="multipart/form-data">

                {% csrf_token %}
                <p>{{ form.non_field_errors }}</p>

                <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>

                <p>
                    {{ form.docfile.errors }}
                    {{ form.docfile }}
                </p>


                <p>{{ form.non_field_errors }}</p>

                <p>{{ form.docfile.label_tag }} {{ form.docfile.help_text }}</p>

                <p>
                    {{ form.docfile.errors }}
                    {{ form.docfile }}
                </p>

                <p><input type="submit" value="Upload"/></p>
            </form>   

            <!-- check error
            {% if form.errors %}
            {% for field in form %}
            {% for error in field.errors %}
            <div class="alert alert-error">
                <strong>{{ error|escape }}</strong>
            </div>
            {% endfor %}
            {% endfor %}
            {% for error in form.non_field_errors %}
            <div class="alert alert-error">
                <strong>{{ error|escape }}</strong>
            </div>
            {% endfor %}
            {% endif %} -->

        </body>

views.py

# -*- coding: utf-8 -*-
from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse

from myproject.myapp.models import Document
from myproject.myapp.forms import DocumentForm
from myproject.myapp.forms import DocumentForm2


def list(request):
    # Handle file upload
    if request.method == 'POST':
        form = DocumentForm(request.POST, prefix="form")
        form2 = DocumentForm2(request.POST, prefix="form2")

        if form.is_valid() or form2.is_valid(): 
            newdoc = Document(docfile=request.FILES['docfile'])
            newdoc.save()

            # Redirect to the document list after POST
            return HttpResponseRedirect(reverse('myproject.myapp.views.list'))
    else:
        form = DocumentForm(prefix="form")  # A empty, unbound form
        form2 = DocumentForm2(prefix="form2")  # A empty, unbound form

    # Load documents for the list page
    documents = Document.objects.all()

    # Render list page with the documents and the form
    return render_to_response(
        'list.html',
        {'documents': documents, 'form': form},
        context_instance=RequestContext(request)
    )

forms.py

# -*- coding: utf-8 -*-

from django import forms


class DocumentForm(forms.Form):
    docfile = forms.FileField(
        label='Select a file'
        )

class DocumentForm2(forms.Form):
    docfile2 = forms.FileField(
        label='Select a file'
        )
Shang Wang
  • 24,909
  • 20
  • 73
  • 94
mr_man
  • 91
  • 2
  • 9

1 Answers1

0

First, you have 2 forms defined in your views method form and form2, but you only add form to your context.

Secondly, you don't put 2 forms in two different <form> tags. You should put them in one so you could submit them at the same time.

Thirdly, not related, but you CANNOT name your views method list. That's a django keyword for data structure list, you could run into huge trouble if you try to use list in other functions in your views file.

Edit:

You keep using variable {{ form.something }} but you have 2 forms, so you just render the first form twice but completely ignored the second form. You should:

<form action="{% url "list" %}" method="post" enctype="multipart/form-data">
    {% csrf_token %}
    {{ form.as_p }}
    {{ form2.as_p }}
    <p><input type="submit" value="Upload"/></p>
</form>

ReEdit:

I'm not sure what caused the 403 to happen, but let's try replace render_to_response with render:

from django.shortcuts import render

def list(request):
    # your code here
    return render(request, 'list.html', {'documents': documents, 'form': form, 'form2': form2})
Shang Wang
  • 24,909
  • 20
  • 73
  • 94
  • Thanks for the tips Shang Wang. I have a little bit trouble understanding your first remark. Where must I add `form2`? – mr_man Feb 05 '16 at 16:31
  • Read the doc for render_to_response: https://docs.djangoproject.com/en/1.9/topics/http/shortcuts/#render-to-response. The `context` arguments are holding all variables that you are going to pass to the template. Right now you have `{'documents': documents, 'form': form}`, but you are missing `form2`. So it should be: `{'documents': documents, 'form': form, 'form2': form2}`. – Shang Wang Feb 05 '16 at 16:34
  • Cheers mate. However, unfortunately it won't upload anything, not even one. – mr_man Feb 05 '16 at 16:45
  • You need to elaborate on what happened when you upload. Are the forms valid? Do you get the files? Add some print statements to see what happend. – Shang Wang Feb 05 '16 at 16:48
  • After I have selected my images and hit upload, I get "This field is required" message on both input fields. I added a print check after the `else:` statement in `views.py` to see whether the forms are valid. Every time I refresh the page, my print statement fires. So it appears that the forms are not valid? Thanks again! – mr_man Feb 05 '16 at 17:19
  • Ah! It is a `403` error: `CSRF verification failed. Request aborted.` My form (please see update in initial post) is correct right? – mr_man Feb 05 '16 at 18:20
  • I don't see anything wrong with that. For the sake of testing, can you add `from django.views.decorators.csrf import csrf_exempt` and `@csrf_exempt` as decorator to your views function and see if that works? – Shang Wang Feb 05 '16 at 18:25
  • When I do that, I don't get redirected to the 403 error pager. Rather, I get the same as I had earlier (This field is required" message on both input fields), and the nothing happens on the page. BUT, I just noticed an error message in the cmd! It says: `: UserWarning: A {% csrf_token %} was used in a template, but the context did not provide the value. This is usually caused by not using RequestContext. "A {% csrf_token %} was used in a template, but the context "` But I do use that requestcontext – mr_man Feb 05 '16 at 18:38
  • I'm not sure, but why do you keep using variable name `form` in your template? You have 2 forms, one is called `form` and the other is `form2` so you should render them separately. – Shang Wang Feb 05 '16 at 18:46
  • Hmm, it is because I tried to model my code after this example here: http://stackoverflow.com/questions/18489393/django-submit-two-different-forms-with-one-submit-button. How would I render separately? – mr_man Feb 05 '16 at 18:50
  • Thanks for the suggestion, but unfortunately it did not work. It loads the 403 error page: `CSRF verification failed. Request aborted.` It should be solveable right? – mr_man Feb 05 '16 at 19:50
  • Shoot, still no luck with this new suggestion. This is really odd, since it is not necessarily a complex thing to do, I think – mr_man Feb 05 '16 at 20:08
  • Dude I don't know what else can I do. I couldn't try it out so I'm running out of ideas. Sorry about that. You might ask a separate question to get more attention about this. – Shang Wang Feb 05 '16 at 20:10
  • Man no worries, you were super helpful :) I will ask a separate question yes. Thanks again for your time and help! – mr_man Feb 05 '16 at 20:16
  • This error `CSRF verification failed. Request aborted.` is raised when you don't pass a good or none CSRF token. You deleted it from template (`{% csrf_token %}`) and marked the function as able to no use it (`@csrf_exempt`). CSRF token protects your web, so don't stop using it unless you know what you are doing and it is totally necessary to remove it. So I suggest to undo those changes and look for the REAL problem (sure, it's not related to CSRF token). – emi Dec 27 '17 at 14:13