generate a minimal header section looks like this:
\begin{verbatim}
-print "Content-type: text/html" # HTML is following
+print "Content-Type: text/html" # HTML is following
print # blank line, end of headers
\end{verbatim}
print "Hello, world!"
\end{verbatim}
-(It may not be fully legal HTML according to the letter of the
-standard, but any browser will understand it.)
-
\subsection{Using the cgi module}
\nodename{Using the cgi module}
standard). Since it may consume standard input, it should be
instantiated only once.
-The \class{FieldStorage} instance can be accessed as if it were a Python
-dictionary. For instance, the following code (which assumes that the
-\code{content-type} header and blank line have already been printed)
+The \class{FieldStorage} instance can be indexed like a Python
+dictionary, and also supports the standard dictionary methods
+\function{has_key()} and \function{keys()}.
+Form fields containing empty strings are ignored
+and do not appear in the dictionary; to keep such values, provide
+the optional \samp{keep_blank_values} argument when creating the
+\class {FieldStorage} instance.
+
+For instance, the following code (which assumes that the
+\code{Content-Type} header and blank line have already been printed)
checks that the fields \code{name} and \code{addr} are both set to a
non-empty string:
form = cgi.FieldStorage()
form_ok = 0
if form.has_key("name") and form.has_key("addr"):
- if form["name"].value != "" and form["addr"].value != "":
- form_ok = 1
+ form_ok = 1
if not form_ok:
print "<H1>Error</H1>"
print "Please fill in the name and addr fields."
return
+print "<p>name:", form["name"].value
+print "<p>addr:", form["addr"].value
...further form processing here...
\end{verbatim}
Here the fields, accessed through \samp{form[\var{key}]}, are
themselves instances of \class{FieldStorage} (or
\class{MiniFieldStorage}, depending on the form encoding).
+The \member{value} attribute of the instance yields the string value
+of the field. The \function{getvalue()} method returns this string value
+directly; it also accepts an optional second argument as a default to
+return if the requested key is not present.
If the submitted form data contains more than one field with the same
name, the object retrieved by \samp{form[\var{key}]} is not a
\class{FieldStorage} or \class{MiniFieldStorage}
-instance but a list of such instances. If you expect this possibility
+instance but a list of such instances. Similarly, in this situation,
+\samp{form.getvalue(\var{key})} would return a list of strings.
+If you expect this possibility
(i.e., when your HTML form contains multiple fields with the same
name), use the \function{type()} function to determine whether you
have a single instance or a list of instances. For example, here's
commas:
\begin{verbatim}
-username = form["username"]
-if type(username) is type([]):
+value = form.getvalue("username", "")
+if type(value) is type([]):
# Multiple username fields specified
- usernames = ""
- for item in username:
- if usernames:
- # Next item -- insert comma
- usernames = usernames + "," + item.value
- else:
- # First item -- don't insert comma
- usernames = item.value
+ usernames = ",".join(value)
else:
- # Single username field specified
- usernames = username.value
+ # Single or no username field specified
+ usernames = value
\end{verbatim}
-If a field represents an uploaded file, the value attribute reads the
+If a field represents an uploaded file, accessing the value via the
+\member{value} attribute or the \function{getvalue()} method reads the
entire file in memory as a string. This may not be what you want.
-You can test for an uploaded file by testing either the filename
-attribute or the file attribute. You can then read the data at
-leisure from the file attribute:
+You can test for an uploaded file by testing either the \member{filename}
+attribute or the \member{file} attribute. You can then read the data at
+leisure from the \member{file} attribute:
\begin{verbatim}
fileitem = form["userfile"]
as a single data part of type
\mimetype{application/x-www-form-urlencoded}), the items will actually
be instances of the class \class{MiniFieldStorage}. In this case, the
-list, file and filename attributes are always \code{None}.
+\member{list}, \member{file}, and \member{filename} attributes are
+always \code{None}.
\subsection{Old classes}
\begin{funcdesc}{parse_multipart}{fp, pdict}
Parse input of type \mimetype{multipart/form-data} (for
file uploads). Arguments are \var{fp} for the input file and
-\var{pdict} for the dictionary containing other parameters of
-\code{content-type} header
+\var{pdict} for a dictionary containing other parameters in
+the \code{Content-Type} header.
Returns a dictionary just like \function{parse_qs()} keys are the
field names, each value is a list of values for that field. This is
easy to use but not much good if you are expecting megabytes to be
uploaded --- in that case, use the \class{FieldStorage} class instead
-which is much more flexible. Note that \code{content-type} is the
-raw, unparsed contents of the \code{content-type} header.
+which is much more flexible.
Note that this does not parse nested multipart parts --- use
\class{FieldStorage} for that.
\end{funcdesc}
\begin{funcdesc}{parse_header}{string}
-Parse a header like \code{content-type} into a main
-content-type and a dictionary of parameters.
+Parse a MIME header (such as \code{Content-Type}) into a main
+value and a dictionary of parameters.
\end{funcdesc}
\begin{funcdesc}{test}{}
\begin{verbatim}
import sys
import traceback
-print "Content-type: text/html"
+print "Content-Type: text/html"
print
sys.stderr = sys.stdout
try:
\begin{verbatim}
import sys
sys.stderr = sys.stdout
-print "Content-type: text/plain"
+print "Content-Type: text/plain"
print
...your code here...
\end{verbatim}
# responsible for its maintenance.
#
-__version__ = "2.2"
+__version__ = "2.3"
# Imports
import urllib
import mimetools
import rfc822
+import UserDict
from StringIO import StringIO
"""
dict = {}
for name, value in parse_qsl(qs, keep_blank_values, strict_parsing):
- if len(value) or keep_blank_values:
- if dict.has_key(name):
- dict[name].append(value)
- else:
- dict[name] = [value]
+ if dict.has_key(name):
+ dict[name].append(value)
+ else:
+ dict[name] = [value]
return dict
def parse_qsl(qs, keep_blank_values=0, strict_parsing=0):
if strict_parsing:
raise ValueError, "bad query field: %s" % `name_value`
continue
- name = urllib.unquote(string.replace(nv[0], '+', ' '))
- value = urllib.unquote(string.replace(nv[1], '+', ' '))
- r.append((name, value))
+ if len(nv[1]) or keep_blank_values:
+ name = urllib.unquote(string.replace(nv[0], '+', ' '))
+ value = urllib.unquote(string.replace(nv[1], '+', ' '))
+ r.append((name, value))
return r
else:
return found
+ def getvalue(self, key, default=None):
+ """Dictionary style get() method, including 'value' lookup."""
+ if self.has_key(key):
+ value = self[key]
+ if type(value) is type([]):
+ return map(lambda v: v.value, value)
+ else:
+ return value.value
+ else:
+ return default
+
def keys(self):
"""Dictionary style keys() method."""
if self.list is None:
# Backwards Compatibility Classes
# ===============================
-class FormContentDict:
+class FormContentDict(UserDict.UserDict):
"""Basic (multiple values per field) form content as dictionary.
form = FormContentDict()
"""
def __init__(self, environ=os.environ):
- self.dict = parse(environ=environ)
+ self.dict = self.data = parse(environ=environ)
self.query_string = environ['QUERY_STRING']
- def __getitem__(self,key):
- return self.dict[key]
- def keys(self):
- return self.dict.keys()
- def has_key(self, key):
- return self.dict.has_key(key)
- def values(self):
- return self.dict.values()
- def items(self):
- return self.dict.items()
- def __len__( self ):
- return len(self.dict)
class SvFormContentDict(FormContentDict):
d = do_test(orig, "POST")
assert d == expect, "Error parsing %s" % repr(orig)
- d = {'QUERY_STRING': orig}
- fcd = cgi.FormContentDict(d)
- sd = cgi.SvFormContentDict(d)
+ env = {'QUERY_STRING': orig}
+ fcd = cgi.FormContentDict(env)
+ sd = cgi.SvFormContentDict(env)
+ fs = cgi.FieldStorage(environ=env)
if type(expect) == type({}):
# test dict interface
assert len(expect) == len(fcd)
assert norm(expect.keys()) == norm(fcd.keys())
assert norm(expect.values()) == norm(fcd.values())
assert norm(expect.items()) == norm(fcd.items())
+ assert fcd.get("nonexistent field", "default") == "default"
+ assert len(sd) == len(fs)
+ assert norm(sd.keys()) == norm(fs.keys())
+ assert fs.getvalue("nonexistent field", "default") == "default"
+ # test individual fields
for key in expect.keys():
expect_val = expect[key]
assert fcd.has_key(key)
assert norm(fcd[key]) == norm(expect[key])
+ assert fcd.get(key, "default") == fcd[key]
+ assert fs.has_key(key)
if len(expect_val) > 1:
single_value = 0
else:
val = sd[key]
except IndexError:
assert not single_value
+ assert fs.getvalue(key) == expect_val
else:
assert single_value
assert val == expect_val[0]
+ assert fs.getvalue(key) == expect_val[0]
assert norm(sd.getlist(key)) == norm(expect_val)
if single_value:
assert norm(sd.values()) == \