Link to home
Start Free TrialLog in
Avatar of sara_bellum
sara_bellumFlag for United States of America

asked on

python cgi handling of html textarea inputs with template substitution

I've written a simple cgi script to process two form elements, a text input and a textarea input, and print user inputs to the form after the user presses the submit button. It works for the text input but not for the textarea. Why? The script and the html page are attached. I'm using python template substitution.
import cgi
import re
import cgitb; cgitb.enable()
from string import Template

form = cgi.FieldStorage()
fields = {}
template_form = 'text_box.html'
name_message = 'Your name: '
comments_message = 'Type in your comments here:'
form_fields = [ 'your_name', 'comments' ]

def print_form(name_message=None, comments_message=None, **kw):

    fields = kw.get('fields', {})

    for field_name in form_fields:
        if isinstance(form.getvalue(field_name), list):
            fields[field_name] = form.getfirst(field_name)
        else:
            fields[field_name] = form.getvalue(field_name)

    for key in fields.keys():
        if fields[key] == None:
            fields[key] = ' '

    if fields['your_name'] != ' ' and fields['comments'] != ' ':
        if len(fields['comments']) > 1000:
            name_message = 'Your name is: '
            comments_message = 'Your comments are too long'
        else:
            name_message = 'Your name is: '
            comments_message = 'We have read your comments and they are:'
            print 'Your name: ', fields['your_name'], '<br/>Your comments:', fields['comments'], '<br/>'
            print '<hr width="50%" align="left">'

    else:
        name_message = 'Your name: '
        comments_message = 'Type in your comments here:'

    try:
        s = Template(open(template_form).read())
        print s.substitute(name_message=name_message, comments_message=comments_message, **fields)

    except IOError:
        print 'Could not read form!'
        sys.exit(1)

print "Content-Type: text/html\n\n"

print_form(name_message=None, comments_message=None, fields=fields)

Open in new window

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Python Form</title>
</head>
<body>
<form method="post" action="text_area.cgi">
    <p>${name_message}<input type="text" name="your_name" maxlength="100" value="${your_name}"></p>
    <p>${comments_message}</p>
    <textarea name="comments" cols="50" rows="10" maxlength="800" value="${comments}"></textarea><br/>
    <input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Open in new window

Avatar of clockwatcher
clockwatcher

Textarea's don't get there initial value based on the value attribute.  They get it based on their content.  Try changing this:

<textarea name="comments" cols="50" rows="10" maxlength="800" value="${comments}"></textarea>

To this:

<textarea name="comments" cols="50" rows="10" maxlength="800">${comments}</textarea>
Avatar of sara_bellum

ASKER

Thanks very much!! That should wrap it up, but I'd like to check a few things before closing this, hopefully tomorrow :)
I was hoping that the problem would be easy to solve but it's not, because forms have more than text boxes and text areas - they also have radio buttons and check boxes, and I don't know how to make them maintain a persistent state with python template substitution. I took a stab at it which I attach - the print statements work, so I'm missing something.

I researched the problem and there's a website that addresses the problem of check boxes and radio buttons at http://www.voidspace.org.uk/python/articles/cgi_web_applications_two.shtml  But this script doesn't address the question of maintaining user inputs in text areas, so I'm still stuck.

I'd rather stick with python template substitution if there's a way to address the problem in that way. Let me know if I need to open a new question.
 
form = cgi.FieldStorage()
fields = {}
template_form = 'text_box.html'
error_message = ' '
form_fields = [ '_charset_', 'your_name', 'red', 'blue', 'green', 'yellow', 'food', 'comments', \
                         'check1', 'check2', 'check3', 'check4', 'check5', 'check6', 'check7', 'submit' ]
check_colors = [ 'red', 'blue', 'green', 'yellow' ]
check_radio = [ 'check5', 'check6', 'check7' ]
check_box = [ 'check1', 'check2', 'check3', 'check4' ]
form_dict = { 'Name': ' ', 'red': ' ', 'blue': ' ', 'green': ' ', 'yellow': ' ', 'Food': ' ', 'Comments': ' ' }
required = ['Name', 'red', 'blue', 'green', 'yellow', 'Food', 'Comments']
errors = []
colors = []

def print_form(error_message=None, **kw):

    fields = kw.get('fields', {})

    for field_name in form_fields:
        if isinstance(form.getvalue(field_name), list):
            fields[field_name] = form.getfirst(field_name)
        else:
            fields[field_name] = form.getvalue(field_name)

    for key in fields.keys():
        #print key
        if fields[key] == None:
            fields[key] = ' '

        for item in check_colors:
            if item == key:
                if form.getvalue(key):
                    fields[key] = 'on'
                    colors.append(key)
                else:
                    fields[key] = 'off'

        for field in form_dict.keys():
            if field == key:
                if fields[key] == 'on':
                    form_dict[field] = 'on'
                else:
                    form_dict[field] = 'off'

        if key == 'red':
            if fields[key] == 'on':
                check1 = 'checked'
                print 'red is on,', check1, 'should be checked <br/>'
            else:
                check1 = ''

        if key == 'blue':
            if fields[key] == 'on':
                check2 = 'checked'
                print 'blue is on,', check2, 'should be checked <br/>'
            else:
                check2 = ''

        if key == 'green':
            if fields[key] == 'on':
                check3 = 'checked'
                print 'green is on,', check3, 'should be checked <br/>'
            else:
                check3 = ''

        if key == 'yellow':
            if fields[key] == 'on':
                check4 = 'checked'
                print 'yellow is on,', check4, 'should be checked <br/>'
            else:
                check4 = ''

        if fields[key] == 'chicken':
            check5 = 'checked'
            print 'chicken was selected, radio button should be checked <br/>'
        else:
            check5 = ''

        if fields[key] == 'beef':
            check6 = 'checked'
            print 'beef was selected, radio button should be checked <br/>'
        else:
            check6 = ''

        if fields[key] == 'fish':
            check7 = 'checked'
            print 'fish was selected, radio button should be checked <br/>'
        else:
            check6 = ''

    form_dict['Food'] = form.getvalue('food')

    if fields['your_name']:
        form_dict['Name'] = fields['your_name']

    if fields['comments']:
        if len(fields['comments']) > 1000:
                errors.append('Your comments are too long!')
        else:
            form_dict['Comments'] = fields['comments']

    if form_dict['Food'] == ' ':
        errors.append('Missing food!')
    elif form_dict['Name'] == ' ':
        errors.append('Missing name!')
    elif form_dict['Comments'] == ' ':
        errors.append('Missing comments!')

    if len(colors) == 0:
        errors.append('Missing color!')

    if form.getvalue('submit'):
        error_message = ' '
        print '<br/>'
        for item in required:
            for field in form_dict.keys():
                if item == field and form_dict[field] != 'off':
                    print field, ':', form_dict[field], '<br/>'
        print '<hr width="50%" align="left">'

        if len(errors) > 0:
            print errors
            error_message = 'Complete all four fields!'
    else:
        error_message = ' '

    try:
        s = Template(open(template_form).read())
        print s.substitute(error_message=error_message, **fields)

    except IOError:
        print 'Could not read form!'
        sys.exit(1)

print "Content-Type: text/html\n\n"

print_form(error_message=None, fields=fields)

Open in new window

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<title>Python Form</title>
</head>
<body>
<form method="post" action="text_area.cgi">
    <div>${error_message}</div>
    <p>Your name: <input type="text" name="your_name" maxlength="100" value="${your_name}"></p>
    <p> Your colors: <br/>
    <input type="checkbox" name="red" value=" " ${check1} />  Red
    <input type="checkbox" name="blue" value=" " ${check2} /> Blue <br />
    <input type="checkbox" name="green" value=" " ${check3} /> Green
    <input type="checkbox" name="yellow" value=" " ${check4} /> Yellow </p>
    <p> Your menu choice:
    <input type="radio" name="food" value="chicken" ${check5} /> Chicken
    <input type="radio" name="food" value="beef" ${check6} /> Beef
    <input type="radio" name="food" value="fish" ${check7} /> Fish </p>
    <p>Your comments</p>
    <textarea name="comments" cols="50" rows="10" maxlength="800">${comments}</textarea><br/>
    <input type="submit" name="submit" value="Submit" />
</form>
</body>
</html>

Open in new window

The reason that what you're doing isn't working is because you're setting a variable named check1 but you're not passing that variable into your template.  You're passing error_message and **fields:

   s.substitute(error_message=error_message, **fields)

Open in new window


Setting fields['check1'] would work:

        if key == 'red':
            if fields[key] == 'on':
                fields['check1'] = 'checked'
                print 'red is on,', fields['check1'], 'should be checked <br/>'
            else:
                fields['check1'] = ''

Open in new window

ASKER CERTIFIED SOLUTION
Avatar of clockwatcher
clockwatcher

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I made some minor edits that I post here for the record (I don't think the radio button values persisted without the else statement) but your feedback clockwatcher is fabulous. Thanks very much!!

It's wonderful to be able to write a script the way I wish to write it rather than depend on the way someone else did simply because their way works (and is posted on the Internet) and mine does not, for reasons which I can't understand. Now I know why there was a problem and I know the fix and life is good.

EE ROCKS
#!/usr/bin/python

import sys
import cgi
import re
import cgitb; cgitb.enable()
from string import Template

form = cgi.FieldStorage()
fields = {}
template_form = 'page_ee.html'
error_message = ' '
form_fields = [ '_charset_', 'your_name', 'red', 'blue', 'green', 'yellow', 'food', 'comments', \
                         'check1', 'check2', 'check3', 'check4', 'check5', 'check6', 'check7', 'submit' ]
check_colors = [ 'red', 'blue', 'green', 'yellow' ]
check_radio = [ 'check5', 'check6', 'check7' ]
check_box = [ 'check1', 'check2', 'check3', 'check4' ]
form_dict = { 'Name': ' ', 'red': ' ', 'blue': ' ', 'green': ' ', 'yellow': ' ', 'Food': ' ', 'Comments': ' ' }
required = ['Name', 'red', 'blue', 'green', 'yellow', 'Food', 'Comments']
errors = []
colors = []

def print_form(error_message=None, **kw):

    fields = kw.get('fields', {})

    for field_name in form_fields:
        if isinstance(form.getvalue(field_name), list):
            fields[field_name] = form.getfirst(field_name)
        else:
            fields[field_name] = form.getvalue(field_name)
            
        if form.getvalue(field_name) == None:
            fields[field_name] = ''

    for color in ('red', 'blue', 'green', 'yellow'):
         
        if color in form:
            fields['color_' + color] = 'checked'
            print "%s is the color that is checked <br/>" % (color)
            colors.append(color)
        else:
            fields['color_' + color] = ''
        
    for meal in ('beef', 'chicken', 'fish'):
        fields['food_' + meal] = ''

    selected_food = fields['food']
    if selected_food != '':
        fields['food_' + selected_food] = 'checked'
        print selected_food, "is the food that is checked <br/>" 
    else:
        fields['food_' + selected_food] = ''
   
    if fields['your_name']:
        form_dict['Name'] = fields['your_name']

    if fields['comments']:
        if len(fields['comments']) > 1000:
                errors.append('Your comments are too long!')
        else:
            form_dict['Comments'] = fields['comments']

    if form_dict['Food'] == ' ':
        errors.append('Missing food!')
    elif form_dict['Name'] == ' ':
        errors.append('Missing name!')
    elif form_dict['Comments'] == ' ':
        errors.append('Missing comments!')

    if len(colors) == 0:
        errors.append('Missing color!')

    if form.getvalue('submit'):
        if len(errors) > 0:
            print errors
            error_message = 'Complete all four fields!'
        else:
            error_message = ' '
    else:
        error_message = ' '

    try:
        s = Template(open(template_form).read())
        print s.substitute(error_message=error_message, **fields)

    except IOError:
        print 'Could not read form!'
        sys.exit(1)

print "Content-Type: text/html\n\n"

print_form(error_message=None, fields=fields)

Open in new window

Very very helpful !!