Tom Kealy Tom Kealy - 4 months ago 9
HTML Question

Saving the content of a <textarea> to file with Bottle

I'm writing a small web portal which will enable users to annotate some text, for a computational linguistics project, and save their annotations to file.

I'm having trouble getting the modified text to be saved.

My page is:

from bottle import template
from project import app
from bottle import request
from bottle import redirect
import random


@app.route('/')
def index():
notices = 'This is a placeholder text for StackOverflow'
return template('annotator/index', package=notices)


@app.route('/annotator/submit', method=['GET'])
def submit():
with open('output.txt', 'w') as outfile:
package = str(request.GET.get('package'))
outfile.write(str(package))
redirect('/')


The layout of my page is:

<!doctype html>
<head>
<link rel="stylesheet" type="text/css" href="/css/style.css">
<title>My App</title>
</head>
<body>
<div class="page">
<h1>NM Annotator Demo V 0.1</h1>
% if package is not '':
<form action='annotator/submit', method="GET">
<textarea name="package" ROWS=20 COLS=70>{{package}}</textarea>
<td><INPUT TYPE=SUBMIT name="package" VALUE="Submit"></td>
</form>
%end
%include
</div>
</body>




And the submit page is:

<form action="annotator/submit" method="post">
<dl>
Thank you
</dl>
</form>
%rebase layout/layout


However, only the word 'submit' is being saved in the file - not the content of the - which is what I want to get saved, as it will be the result of the annotation.

This is my first web app, and I'm a bit confused.

Answer

Your textarea and your submit form items are both named "package".

Change your button to this and see if that helps:

<INPUT TYPE=SUBMIT name="submit" VALUE="Submit">

EDIT: Explanation

The problem with having two form items that have the same name is that your application receives them both, on the query string. For example,

http://yourserver.com/annotator/submit?package=sometext&package=Submit

In your app, you'll effectively get a dict of the query args, and it will either look like {'package': 'sometext'} or {'package': 'Submit'}. Which one you get depends entirely upon the application (Bottle), but the most likely implementation--to process the query args in order--would result in the second value taking precedence, as it overwrites the first.

Most web frameworks expose a way to get all query args for a given name; in Bottle, it's request.query.getall. So request.query.getall('package') would return ['sometext', 'Submit']. But in your case it makes much more sense to avoid the name collision in the first place, rather than keep it and then retrieve multiple values.

Hope that helps!