Running a python script with HTML button - python

How can I call a python script when the button is html file is clicked?
I am trying to change the language of the website by clicking the button. This is what I have done so far, but I am getting an error when I hit the button "page not found" and "The current URL, foo, didn't match any of these." What am I doing wrong
login.html
<form action="/foo" method="post">
<input type="submit" name = "first_button" value="French">
<input type="submit" name = "second_button" value="Spanish">
</form>
views.py
from app import foo
def get_language_from_client(request):
new_lang= foo()
if new_lang=="fr":
client_lang="fr"
else:
client_lang = translation.get_language_from_request(request)
print "client_lang:", client_lang
if "en" in client_lang:
return 0
elif "nl" in client_lang:
return 1
elif "fr" in client_lang:
return 2
elif "pl" in client_lang:
return 3
elif "ru" in client_lang:
return 4
else:
print "Unknown language code:", client_lang
return 2
app.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('login.html')
#app.route('/foo')
def foo():
return "fr"
if __name__ == '__main__':
app.run()
My directory structure looks like
scriboxapp
-templates
-login.html
-views.py
-app.py

I would recommend using Flask for this.
Here's an example of what you can do:
index.html:
<form action="/foo" method="POST">
<input type="submit" value="French">
</form>
app.py:
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/foo', methods=['GET', 'POST'])
def foo():
'''execute whatever code you want when the button gets clicked here'''
return
if __name__ == '__main__':
app.run()
When you run your app.py file and navigate to the URL where the Flask webserver is running, which in this case is localhost, you will be presented with the index.html file.
In the above example, you can see that the button containing the value French will execute your /foo route. Your function with the proper route decorator /foo is where you can execute your desired code.
To get this working, your directory structure should look something like this:
- app
- templates
- index.html
- app.py

Related

How to prevent uploaded files from having the same name Flask Python

I am trying to build a website in python using flask that takes file uploads and saves them to a folder (called uploads). However, when two files with the same name are uploaded, the first one is overwritten by the last one. How can I prevent this in a way that means that I don't lose any files? Would adding a timestamp to the filename help or would there still be an issue if two files are uploaded at the same time?
Thanks!
Filesystem
FlaskProject:
├───static
├───templates
├───uploads
└───app.py
Html
{%extends "base.html" %}
{%block content%}
<p>
<h2>Upload Below!</h2>
<div></div>
<form action = "http://localhost:5000/upload_complete" method = "POST"
enctype = "multipart/form-data">
<input type = "file" name = "file" />
<input type = "submit"/>
</form>
{% endblock %}
Python
from flask import Flask, redirect, url_for, render_template, request
from werkzeug.utils import secure_filename
import os
app = Flask(__name__)
app.config['UPLOAD_FOLDER'] = "D:/Me/FlaskProject/uploads"
#app.route('/upload')
def upload():
return render_template("upload.html", page="Upload Images")
#app.route('/upload_complete', methods = ['GET', 'POST'])
def upload_complete():
if request.method == 'POST':
f = request.files['file']
f.save(os.path.join(app.config['UPLOAD_FOLDER'], secure_filename(f.filename)))
return redirect(url_for('upload_complete'))
return render_template("upload_complete.html", page="Upload Complete")
if __name__ == '__main__':
app.debug = True
app.run()
app.run(debug = True)
(upload_complete.html is just a thank you screen)
You can generate an uuid and update the filename with it.
You can generate uuid like this,
import uuid
... your code ..
hash_value = uuid.uuid4().hex
f.save(os.path.join(app.config['UPLOAD_FOLDER'], hash_value + secure_filename(f.filename)))

How can I yield a template over another in flask?

I have been working on a project in flask and I am stuck on one part where I need to figure out how to yield one flask template over another.
To illustrate what I mean, for example, I have a program like this.
main.py
from flask import Flask, stream_with_context, Response, render_template
app = Flask('app')
#app.route('/')
def hello_world():
def generate():
yield render_template('index.html')
yield render_template('index2.html')
return Response(stream_with_context(generate()))
app.run(host='0.0.0.0', port=8080)
index.html
<h3>Hi</h3>
index2.html
<h3>Bye</h3>
Running main.py returns:
Hi
Bye
Even though this makes sense, my goal is to make it result in just Bye which should replace Hi. I tried other paths like returning both but none of them worked. Any ideas on how I can do this?
It's not your case, but if you'd like to stream a template with static content, here's a way to do it. I'll be using the sleep() method to suspend the execution for 1 second.
from flask import Flask, stream_with_context, request, Response, flash
import time
from time import sleep
app = Flask(__name__)
def stream_template(template_name, **context):
app.update_template_context(context)
t = app.jinja_env.get_template(template_name)
rv = t.stream(context)
rv.disable_buffering()
return rv
data = ['Hi', 'Bye']
def generate():
for item in data:
yield str(item)
sleep(1)
#app.route('/')
def stream_view():
rows = generate()
return Response(stream_with_context(stream_template('index.html', rows=rows)))
if __name__ == "__main__":
app.run()
where templates/index.html:
{% for item in rows %}
<h1>{{ item }}</h1>
{% endfor %}
See streaming from templates in the documentation.
You would have to do you function different to use a generator like this.
from flask import Flask, stream_with_context, Response, render_template
app = Flask('app')
def page_generator():
yield render_template('index.html')
yield render_template('index2.html')
generator_obj = None
#app.route('/')
def hello_world():
global generator_obj
generator_obj = generator_obj or page_generator()
return Response(stream_with_context(next(generator_obj)))
app.run(host='0.0.0.0', port=8080)
I don't know for sure if this will work in flask.
Note that after you call hello_world twice this will fail unless you reset generator_obj to None on StopIteration.

How to print output using only a POST Method?

How can I print something like this:
{
username = admin
email = admin#localhost
id=42
}
With only using a method = ['POST'] and without using render_template?
PS: I already made it run with ['GET']
Here's my code:
from flask import Flask, jsonify, request
app = Flask(__name__)
#app.route('/', methods=['POST'])
def index():
if request.method == 'POST':
return jsonify(username="admin",
email="admin#localhost",
id="42")
else:
if request.method == 'POST':
return jsonify(username="admin",
email="admin#localhost",
id="42")
if __name__ == "__main__":
app.run()
And what I get is a 405 Method error.
Hey make sure your trailing stashes in your html are correct.
you may refer to : Flask - POST Error 405 Method Not Allowed and flask documentation : http://flask.pocoo.org/docs/0.10/quickstart/
this
<form action="/" method="post">
and this is same same but different
<form action="" method="post">
Accessing it without a trailing slash will cause Flask to redirect to the canonical URL with the trailing slash.
Given your error 405, I am suspecting that this is your problem. GET is fine, because you will just be redirected.
Try returning the form (as biobirdman said) on a GET request. Not sure why you need the request.method == 'POST' conditional statement. The parameter methods=['POST'] in the route should suffice.
Try this:
from flask import Flask, jsonify, request
app = Flask(__name__)
#app.route('/', methods=['POST'])
def index():
return jsonify(username="admin", email="admin#localhost", id="42")
#app.route('/', methods=['GET'])
def form():
return "<form action='/' method='POST'>" \
"<input type='submit'>" \
"</form>"
if __name__ == "__main__":
app.run()

File Upload Hangs with Flask

I am trying to upload a file but the browser spinner rolls forever, server logs don't show updates and the file doesn't get uploaded. It sure is a newbie error but I have no clue what that is:-
static/index.html :-
html
form action="http://127.0.0.1:5000/upload" method="post" enctype="multipart/form-data"
input type="file" name="db"/
input type="submit" value="upload"/
/form
html
app.py
from flask import Flask
from flask import request
from werkzeug import secure_filename
app = Flask(__name__)
#app.route('/')
def hello_world():
return 'Hello World!'
#app.route('/upload', methods=['GET', 'POST'])
def upload_file():
print 'upload_file'
if request.method == 'POST':
print 'post'
f = request.files['db']
f.save(secure_filename(f.filename))
if __name__ == '__main__':
app.run(debug=True)
Thanks
Env: Flask 0.9, Jinja2-2.6 and Werkzeug-0.8.3 with Python 2.7 on Win7 x64 with IE9 and Chrome
The docs say you should use enctype="multipart/form-data".
Also, I might try method="POST" (uppercase), if only because defensive coding is a good habit, the defensive maneuver here being not assuming that Flask is bug-free.

Bad Request Error with flask, python, HTML, unusual initialization behavior with flask.request.form

I'm writing a web-app using flask, python and HTML. My issue is that the first time I load the a webpage, I get the following error
Bad Request The browser (or proxy) sent a request that this server
could not understand.
I'm able to get the page to load eventually by "tricking" first running it without any flask.request.form calls, and then putting them back in (details below). Something must be going wrong in my initialization. I'm new to flask and using python with HTML.
Assume I'm working from a directory called example. I have a python script called test.py and an HTML template called test.html with the following directory structure:
\example\test.py
\example\templates\test.html
My python script test.py is:
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
result = flask.request.form['result']
return flask.render_template('test.html', result=result)
# return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
and my HTML in test.html is
<html>
<head>
</head>
<body>
<form action="/" method="post">
Enter something into the box:
<input type="text" name="result"/><br>
<input type="submit" value="Execute!"/>
</form>
</body>
</html>
Steps to reproduce the error
1: Run the test.py script, and open up the URL in a browser
Running on http://127.0.0.1:5000/
You should see the following error
Bad Request The browser (or proxy) sent a request that this server
could not understand.
2: Comment out the first 2 lines of the def get(self) function and uncomment the 3rd line of the def get(self) function so that test.py looks like this
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
# result = flask.request.form['result']
# return flask.render_template('test.html', result=result)
return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
3: Refresh the URL, and you will see that things work (though I ultimately want to be able to return the value of result
4: Now, switch the lines that are commented out again. I.e, uncomment the first 2 lines of the def get(self) function and comment out the 3rd line of the def get(self) function so that test.py looks like this
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
class View(flask.views.MethodView):
def get(self):
result = flask.request.form['result']
return flask.render_template('test.html', result=result)
# return flask.render_template('test.html')
def post(self):
return self.get()
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
app.debug = True
app.run()
5: Refresh the URL and now you see things will be working as desired.
This is just a toy example illustrating the real problem exhibiting this weird behavior of how I have to "trick" my browser into showing me this webpage. The
The issue here is that you are attempting to access POSTed variables in a method that will only handle GET requests. When you attempt to access a query string or POST parameter that is not set Flask will, by default, raise a BadRequest error (because you are asking for something that the person hitting the page did not supply).
What happens if the key does not exist in the form attribute? In that case a special KeyError is raised. You can catch it like a standard KeyError but if you don’t do that, a HTTP 400 Bad Request error page is shown instead. So for many situations you don’t have to deal with that problem.
If you need to access a variable from either request.args (GET) or request.form (POST) and you don't need it to be set use the get method to get the value if it is there (or None if it is not set.
# Will default to None
your_var = request.form.get("some_key")
# Alternately:
your_var = request.form.get("some_key", "alternate_default_value")
Here's an alternate way of structuring your code:
import sys
import flask, flask.views
app = flask.Flask(__name__)
app.secret_key = "bacon"
app.debug = True
class View(flask.views.MethodView):
def get(self):
"""Enable user to provide us with input"""
return self._default_actions()
def post(self):
"""Map user input to our program's inputs - display errors if required"""
result = flask.request.form['result']
# Alternately, if `result` is not *required*
# result = flask.request.form.get("result")
return self._default_actions(result=result)
def _default_actions(self, result=None):
"""Deal with the meat of the matter, taking in whatever params we need
to get or process our information"""
if result is None:
return flask.render_template("test.html")
else:
return flask.render_template("test.html", result=result)
app.add_url_rule('/', view_func=View.as_view('main'), methods=['GET', 'POST'])
if __name__ == "__main__":
app.run()

Categories