3
form= cgi.FieldStorage()
print form

Prints: FieldStorage(None, None, 'age=10&name=joe').

How do I get the data from that form?

I can't use form[FieldKey], because there is no field key.

form['age'] returns a blank string

I'm using Python 2.7.

ggorlen
  • 44,755
  • 7
  • 76
  • 106
Davide Andrea
  • 1,357
  • 2
  • 15
  • 39

4 Answers4

2

This is not an answer. I don't know what's wrong. However, I don't have Python 2 on this computer. I've just run some code on repl.it.

Here's what happens.

FieldStorage on repl.it

It works as it's meant to. Apparently there's something peculiar about your setup. If I think of anything I'll come back.

Bill Bell
  • 21,021
  • 5
  • 43
  • 58
  • Indeed, if I call the script from a web browser, form.keys() does work. You're right: there must be something peculiar about the way the script behaves when called by another script, remotely. I do know that when I "print form", the data look different. Thanks for working with me. – Davide Andrea Sep 22 '17 at 00:03
2

This happens when FieldStorage parses "plain" POST data, as opposed to a form for example. If the content-type of the HTTP request is application/x-www-form-urlencoded however, it will know what to do.

This is the HTML file that has a single send button, once it is clicked, the name and age data are sent to the proc.py script, after the header is set to what the Python CGI library likes.

<html><body>
<button type="button" onclick="sendData()">Send</button>
<div id="content">No reponse from script yet.</div>
<script>
function sendData() {
    var http = new XMLHttpRequest();
    http.onreadystatechange = function() {
        if (this.readyState == 4 && this.status == 200) {
        document.getElementById('content').innerHTML = this.responseText;
        }
    };
    http.open('POST', '/cgi-bin/proc.py', true);
    http.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
    http.send('age=10&name=joe');
}
</script>
</body></html>

And proc.py spits these value back:

#!/usr/bin/env python
import cgi
data = cgi.FieldStorage()
print 'Content-type: text/html\n'
print data['name'].value
print '<br />'
print data['age'].value
fheshwfq
  • 303
  • 3
  • 11
  • Thank you for answering a question I asked more than 1 year ago, and which I never solved. Next time I work on that project I will try your solution, and get back to you. Thanks! – Davide Andrea Dec 13 '18 at 17:54
  • 1
    fheshwfq Update: I am back into that project. The Ajax code _does_ use http.setRequestHeader('content-type', 'application/x-www-form-urlencoded') So, I really don't know what's going on. I just wanted to update you and thank you once more. – Davide Andrea Jan 08 '19 at 17:02
2

Other answers have explained why there was a problem with the request and how to fix it, but I think it might be helpful to better understand the FieldStorage object so you can recover from a bad request.

I was mostly able to duplicate your state using this:

from cgi import FieldStorage
from StringIO import StringIO

f = FieldStorage(
    fp=StringIO("age=10&name=joe"), 
    headers={"content-length": 15, "content-type": "plain/text"}, 
    environ={"REQUEST_METHOD": "POST"}
)

print(f) # FieldStorage(None, None, 'age=10&name=joe')

This will fail as expected:

f["age"] # TypeError: not indexable
f.keys() # TypeError: not indexable

So FieldStorage didn't parse the query string because it didn't know it should, but you can make FieldStorage manually parse it:

f.fp.seek(0) # we reset fp because FieldStorage exhausted it
# if f.fp.seek(0) fails we can also do this:
# f.fp = f.file
f.read_urlencoded()

f["age"] # 10
f.keys() # ["age", "name"]

If you ever need to get the original body from FieldStorage, you can get it from the FieldStorage.file property, the file property gets set when FieldStorage parses what it thinks is a plain body:

f.file.read() # "age=10&name=joe"

Hope this helps other fellow searchers who stumble on this question in the future.

Jaymon
  • 5,363
  • 3
  • 34
  • 34
1

You can try

import cgi

form = cgi.FieldStorage()
print form.getvalue("age")

as described in the more general thread How are POST and GET variables handled in Python?

ggorlen
  • 44,755
  • 7
  • 76
  • 106