Trying to write a simple app that:
Presents an html form to get to get input data (a greeting and a name).
Displays the data in the browser, and then (here is the part I cannot figure out)
Saves the input form data to a simple .txt file
Here is the python code:
import web
urls = (
'/hello', 'Index'
)
app = web.application(urls, globals())
render = web.template.render('templates/', base='layout')
class Index(object):
def GET(self):
return render.hello_form() # returns form to browser
def POST(self): # gets name and greeting data back
form = web.input(name="Nobody", greet="Hello")
greeting = "%s ... %s" % (form.greet, form.name)
return render.index(greeting = greeting) #displays index.html
with open ('projects/forms/ninja.txt)', 'w') as out_file:
out_file.write(form.getValue("greet"))
out_file.write(form.getValue("name"))
if __name__ == "__main__":
app.run()
Here is the hmtl form:
<h1>this is hello_form</h1>
<form action="/hello" method="POST">
A Greeting: <br>
<input type="text" name="greet">
<br/>
Your Name: <br>
<input type="text" name="name">
<br/>
<input type="submit">
</form>
I have searched other answers, including this one:
how to store html form data into file
But I cannot seem to find the information to get this going.
You're performing a POST request on /hello with this line.
<form action="/hello">
However, you haven't defined a controller for this route. As a result, nothing happens.
Either make a POST on /Index or create a handler for /hello
Also, I would highly recommend a framework for this. Something small, like Flask.
Related
I have the code below in my Python script:
def cmd_wui(argv, path_to_tx):
"""Run a web UI."""
from flask import Flask, flash, jsonify, render_template, request
import webbrowser
app = Flask(__name__)
#app.route('/tx/index/')
def index():
"""Load start page where you select your project folder
or load history projects from local DB."""
from txclib import get_version
txc_version = get_version()
prj = project.Project(path_to_tx)
# Let's create a resource list from our config file
res_list = []
prev_proj = ''
for idx, res in enumerate(prj.get_resource_list()):
hostname = prj.get_resource_host(res)
username, password = prj.getset_host_credentials(hostname)
return render_template('init.html', txc_version=txc_version, username=username)
Also, I have an HTML form in init.html:
<form>
<input type="text" id="projectFilepath" size="40" placeholder="Spot your project files">
<input type="button" id="spotButton" value="Spot">
</form>
How can I pass the user input from "projectFilepath" when a user clicks "spotButton" on a variable in my python script?
I'm new in Python and Flask, so forgive me if I make any mistakes.
The form tag needs some attributes set:
action: The URL that the form data is sent to on submit. Generate it with url_for. It can be omitted if the same URL handles showing the form and processing the data.
method="post": Submits the data as form data with the POST method. If not given, or explicitly set to get, the data is submitted in the query string (request.args) with the GET method instead.
enctype="multipart/form-data": When the form contains file inputs, it must have this encoding set, otherwise the files will not be uploaded and Flask won't see them.
The input tag needs a name parameter.
Add a view to handle the submitted data, which is in request.form under the same key as the input's name. Any file inputs will be in request.files.
#app.route('/handle_data', methods=['POST'])
def handle_data():
projectpath = request.form['projectFilepath']
# your code
# return a response
Set the form's action to that view's URL using url_for:
<form action="{{ url_for('handle_data') }}" method="post">
<input type="text" name="projectFilepath">
<input type="submit">
</form>
You need a Flask view that will receive POST data and an HTML form that will send it.
from flask import request
#app.route('/addRegion', methods=['POST'])
def addRegion():
...
return (request.form['projectFilePath'])
<form action="{{ url_for('addRegion') }}" method="post">
Project file path: <input type="text" name="projectFilePath"><br>
<input type="submit" value="Submit">
</form>
So I created a small flask program which would take a file , do some processing and returns a stream of data using yield.
I am using html form for file upload and submit. The form sends file to a python script and returns the output. The issue is that the output is presented onto a different page because of the form action attribute whereas I need the output on the same page. Probably inside a div tag.
index.html
<script>
if (!!window.EventSource) {
var source = new EventSource('/upload');
source.onmessage = function(e) {
console.log(e)
var byte = e.data;
var res = byte.split(/\s/);
console.log(res[0])
$("#morse").text(res[0].slice(1,));
}
}
</script>
<form action="/upload" method=post enctype=multipart/form-data >
<p><input type="file" name="file" >
<input type="submit" value="Upload" id="search_form_input">
</form>
<div id="morse" class="info">nothing received yet</div> // this is where is need my data
Python code
#app.route('/')
def index():
return render_template('index.html')
#app.route("/upload", methods=['GET', 'POST'])
def streambyte():
if request.method == 'POST':
f = request.files['file']
list_of_items = unAssign(f) # some file processing
def events():
for i in list_of_items:
yield "data: %s\n\n" % (i)
time.sleep(1) # an artificial delay
return Response(events(), content_type='text/event-stream')
This streams the data on http://localhost:5000/upload whereas I need it on http://localhost:5000.
I tried using redirect with Response but it failed saying TypeError: 'generator' object is not callable
You may not need JavaScript to do this...
Since you need the result on the 'index.html' page (i.e http://localhost:5000), you need to create two routes for the same index page.
The first route will load the fresh form (method attribute not set), while the second will reload the process form (method attribute is set to POST). Both routes will point to same index page.
Here below is how your code should look like:-
index.html
<!DOCTYPE html>
<html>
<head>
<title>Flask App - Output data on same page after form submit</title>
</head>
<body>
<form method=post enctype=multipart/form-data >
<p><input type="file" name="file" >
<input type="submit" value="Upload" id="search_form_input">
</form>
<div id="morse" class="info">nothing received yet</div>
<h3>{{ result }}</h3>
<h3>{{ file_path }}</h3>
<!-- this is where is need my data -->
</body>
</html>
Python code
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route("/", methods=['GET', 'POST'])
def streambyte():
# your file processing code is here...
f = request.files['file']
your_script_result = 'This variable holds the final data output'
# your file processing code is here...
return render_template('index.html', file_path = f, result = your_script_result)
if __name__ == '__main__':
app.run(debug=True)
Read more from this link: Send data from a textbox into Flask?
I have a rather silly question.
I am trying an app and have two forms on it:
Enter a zip code (submit button)
or
Login if you already have a user id. (submit button)
Now in my code (python using web.py framework) i have two def POST(self) but which one will the first form and the second login form call?
I am super confused. Now my friend tells me html cannot have two different forms.
Here is the code and the form is incomplete - i am just trying to get the methods running well before I start grabbing more data and building a db schema.
import web
from web import form
render = web.template.render('templates/')
urls = (
'/', 'index'
)
myform = form.Form(
form.Textbox("Zip Code",
form.regexp('^\d{5}$', 'Not a zip code'),
description='Enter a 5 digit zip code',
maxlength = '5'),
)
myloginform = form.Form(
form.Textbox("Username",
form.regexp('^[^<>\s\#]+(\#[^<>\s\#]+(\.[^<>\s\#]+)+)$', 'Invalid username'),
description='Enter your username'),
)
class index:
def __init__(self): ** i still dont know wtf this does..
pass
def GET(self):
form = myform()
myloginform1 = myloginform()
return render.index(form,myloginform1)
def POST(self):
form = myform()
if not form.validates():
return render.index(form)
else:
return "The zip code you are located is: %s" % (form['Zip Code'].value)
def POST(self):
myloginform1 = myloginform()
if not myloginform1.validates():
return render.index(myloginform1)
else:
return "Welcome %s" % (myloginform1['Username'].value)
class testfunc:
def GET(self):
return "Test function returning!"
if __name__ == "__main__":
app = web.application(urls, globals())
app.run()
The index.html is below
$def with (form, myloginform1)
<html>
<head><title>8reps Welcome.. </title></head>
<body>
<h3>Hi</h3>
<p> Lets find some results in your area.. </p>
<form name="main" method="post">
$if not form.valid: <p class="error">Try again...</p>
$:form.render()
<input type="submit" /> </form>
<p> Already registered? Login as a user..</p>
<form name="login" method="post">
$if not myloginform1.valid: <p class="error">Try again..</p>
$:myloginform1.render()
<input type="submit" />Login</form>
</form>
</body>
</html>
Thank you!!
you may have as many forms on the page as you want, the only issue is how you will handle them.
there are 2 options:
two separate backends e.g. /login and /zip to handle POSTs from forms - in the form tag you will need to add action attribute to direct POSTs properly
single /index where you can handle both forms, but then you need to recognize which form was posted, e.g. by presence of some named field (you can use submit input with the same name but different values:
<input name="submit" type="submit" value="Zip" />
and for the second form:
<input name="submit" type="submit" value="Login" />
then you will know which form was posted by checking value of sent "submit" field.
for sure, you can't have 2 methods wit the same name in class definition.
I have a python file and an html file that interact with each other through the jinja2 environment in a manner similar to the one in this tutorial.
The following code controls the interaction between the html file and the python file:
class MainPage(webapp2.RequestHandler):
def get(self):
submission_query = Submission.query().order(-Submission.score)
submissions = submission_query.fetch(10)
template_values = {
'Submission' : Submission,
'submissions' : submissions,
}
template = JINJA_ENVIRONMENT.get_template('index.html')
self.response.write(template.render(template_values))
app = webapp2.WSGIApplication([
('/', MainPage),
('/create', CreateSubmmission),
('/voteup', VoteUp),
], debug=True)
I have a ndb model as follows:
class Submission(ndb.Model):
username = ndb.StringProperty()
placename = ndb.StringProperty()
link = ndb.StringProperty()
score = ndb.IntegerProperty()
I have an html form to create a new Submission as follows:
<form action="/create" method="post">
add a new location: <br>
your name:<div><textarea name="username" rows="2" cols="60"></textarea></div>
placename:<div><textarea name="placename" rows="2" cols="60"></textarea></div>
url:<div><textarea name="link" rows="2" cols="60"></textarea></div>
<div><input type="submit" value="Post"></div>
</form>
Using this request handler:
class CreateSubmmission(webapp2.RequestHandler):
def post(self):
submission = Submission()
submission.username = self.request.get('username')
submission.placename = self.request.get('placename')
submission.link = self.request.get('link')
submission.score = 0
submission.put()
self.redirect('/')
I have a section in my html which prints out each Submission along with a button for upvoting it:
{% for Submission in submissions %}
<p>
{{Submission.username}} posted:
<strong>{{Submission.placename}}</strong> <br>
score:{{Submission.score}}<br>
<!--Vote up button-->
<form action="/voteup?submission={{Submission}}" method="post">
<div><input type="submit" value="voteup"></div>
</form>
</p><br><br>
{% endfor %}
The upvoting is handled by the following python class:
class VoteUp(webapp2.RequestHandler):
def post(self):
submission = self.request.get('Submission')
submission_key = submission.put()
the_submission = submission_key.get()
the_submission.score +=1
the_submission.put()
self.redirect('/')
When pressing the button, the value of the respective Submission's score attribute should increase by one.
The code is implemented on the website sunlit-hook-91816.appspot.com. As can be seen on that site, pressing the upvote button generates the following error:
File "/base/data/home/apps/s~sunlit-hook-91816/1.383863233180213164/guestbook.py", line 52, in post
submission_key = submission.put()
AttributeError: 'str' object has no attribute 'put'
It appears that the VoteUp class is somehow unable to modify the value of Submission.score.
I am using the information found here but I can't figure out how to correctly apply it this problem. Can anyone tell me of a way to make the VoteUp class modify the Submission.score?
You're using the Submission object like it can be passed along between html/python code but it can't, you must add a reference in the form and dereference it back in you server.
Do this in the vote form:
<form action="/voteup?submission={{Submission.key.urlsafe()}}" method="post">
<div><input type="submit" value="voteup"></div>
</form>
We're getting the key of the submission in a format safe for http transport, so it can arrive back to the server unaltered.
Now when processing the vote, we can recreate the key and get the correct object:
class VoteUp(webapp2.RequestHandler):
def post(self):
submission = self.request.get('submission')
submission_key = ndb.Key(urlsafe=submission)
the_submission = submission_key.get()
the_submission.score +=1
the_submission.put()
self.redirect('/')
As you can see we're just recreating the key based on the formatted string we printed in the form.
Another way you could do this to make it even better is to use an extra input in the form:
<form action="/voteup" method="post">
<input name="submission" type="hidden" value="{{Submission.key.urlsafe()}}">
<div><input type="submit" value="voteup"></div>
</form>
Your code will work the same way, but I find it easier to read and maintain.
form="""
<textarea>%s</textarea>
"""
I am trying to make a post request using the textarea input, and show the post input in the textarea again and I am able to do that.
But, my problem is in the beginning when I first go to see the page, I see the %s in the textarea box. How do I hide the %s? I am using the old python, I think it is 2.7
form="""
<form method="post">
<textarea name="text">%s</textarea>
<br>
<input type="submit">
</form>
"""
class MainPage(webapp2.RequestHandler):
def get(self):
self.response.write(form)
def post(self):
foo="posted to the box"
self.response.write(form %foo)
app = webapp2.WSGIApplication([('/', MainPage)], debug=True)
Put something in its place.
print form % ('',)
Try following code
print form.replace('%s', '')
Easier, just put %s as value parameter:
<textarea name="text" value="%s"></texarea>
this will create a nice blank textarea ;)