This question already has answers here:
Python - Flask Default Route possible?
(4 answers)
Closed 7 months ago.
I have a question about Flask.
I want to use one endpoint to handle requests.
To do so, I need to take url in router like:
#app.route("/<url>", methods=['GET','POST'])
def home(url):
base_url = "https://www.virustotal.com/"
my_url = base_url + url
For example, I will sent request to my Flask app as " localhost:5000/api/v3/files/samehashvalue "
and it will combine it with virustotal url.
my_url will something like = virustotal.com/api/v3/files/samehashvalue
How can I pass /api/v3... to my router? Without using parameters like ?url=...
I'd suggest reading redirects from the Flask docs as well as url building.
With your specific example you can obtain the url from the route and pass it into your Flask function. It's then just a case of using redirect and an f string to redirect to that new url.
# http://localhost:5000/test redirects to
# https://www.virustotal.com/api/v3/files/test
from flask import Flask, redirect
app = Flask(__name__)
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def url_redirector(path):
return redirect(f'https://www.virustotal.com/api/v3/files/{path}')
if __name__ == '__main__':
app.run(debug=True)
I am not sure if this is correct, but I assume that you can specify the path in #app.route if it is a fixed path. For example:
#app.route("/api/v3/files", methods=['GET','POST'])
def home(url):
base_url = "https://www.virustotal.com/api/v3/files/"
Then the hash value only can be passed as a parameter.
Please let me know if I misunderstood your question and I will edit this answer.
Related
how can I dynamically pass all of the GET parameters from one url to another via flask?
This is currently what I am doing:
import os
from flask import Flask,redirect
from flask import request
from flask import url_for
app = Flask(__name__)
#app.route('/')
def hello():
return redirect(url_for("https://myurl.com", **request.args))
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
I can't really do it statically. What I am trying to accomplish:
myflaskserver:5000/page?url=google.com&header=body&identity=flash -> https://myurl.com/page?url=google.com&header=body&identity=flash
myflaskserver:5000/dance?url=dance.com&function=dancer&move=quality-> https://myurl.com/dance?url=dance.com&function=dancer&move=quality-
myflaskserver:5000/quit?host=google.com&language=english&password=test1234-> https://myurl.com/quit?host=google.com&language=english&password=test1234
With minimal code, without procedurally having to use if statements, or doing it statically with GET parameters for each page.
Thank you.
Because of the way that the question is phrased, it seems that you are looking for a way to perpetuate the url parameters only. In other words, you're not asking how to perpetuate the url page path (or "routes" in flask terminology), perhaps because you already have a strategy for that in mind.
If that assumption is incorrect, see my note near the bottom of this answer.
It also seems that you prefer passing the parameters as url parameters (versus passing the same data in the request header or payload).
If both these assumptions are correct, then the following approach may work for you:
Use the query_string method of request. This method returns all the url parameters as a bytes object (meaning you probably will need to decode it to a string if you wish to join it to your new url string).
import os
from flask import Flask,redirect
from flask import request
app = Flask(__name__)
#app.route('/')
def hello():
request_parameters = request.query_string.decode('utf-8')
return redirect("https://myurl.com?{0}".format(request_parameters))
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
Given the first url in your example...
myflaskserver:5000/page?url=google.com&header=body&identity=flash
...the statement request.query_string.decode('utf-8') would return the string "url=google.com&header=body&identity=flash", which is then appended to your endpoint "https://myurl.com?".
Notice ? needs to be added to the endpoint before joining with request.query_string.
Passing page paths (i.e. routes)
This was not explicitly asked in the question, so I won't go into much detail. But if you need to parse the route from the request, you could use request.url_rule, which will return everything after the domain and before the url parameters.
import os
from flask import Flask,redirect
from flask import request
app = Flask(__name__)
#app.route('/hello')
def hello():
request_parameters = request.query_string.decode('utf-8')
route = request.url_rule
return redirect("https://myurl.com{0}?{1}".format(route,request_parameters))
if __name__ == '__main__':
# Bind to PORT if defined, otherwise default to 5000.
port = int(os.environ.get('PORT', 5000))
app.run(host='0.0.0.0', port=port)
Or you could look into flask.referrer, which will return the referring url from the request header if it is available, which it sometimes isn't, such as in cross-origin scenarios of local testing.
Sidebar
For the information of anyone passing by this post, it may be helpful to mention why the request as written in the question will fail:
When the endpoint "https://myurl.com" of url_for is called, it will fail because the method expects an endpoint (or route, in flask terminology) defined by your app (versus an external endpoint with schema and domain) when called from an active request like this.
I have tried a lot of things but nothing is working. It always gives me the "Incomplete response received from application" message in the navigator.
My code is:
import sys
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def application():
uri = request.args.get('url')
message = 'It works!\n'
response = '\n'.join([message, uri])
return response
The problem is or in the #app.route('/') line or in the uri = request.args.get('url').
I just want to call the with the navigator like http://example.com/script/?url=hello.
I tried changing #app.route('/') to #app.route('/script') and #app.route('/script/') but nothing is working... any ideas?
Thanks a lot!
For future readers: note that the original question has been edited in response to this suggestion.
First issue: You seem to be using some very low-level WSGI implementation when Flask does a lot of the sugar for you. Consider testing with a function that lets Flask do the work and then expand as needed.
import sys
from flask import Flask, request
app = Flask(__name__)
#app.route('/')
def test():
uri = request.args.get('url')
message = 'It works!\n'
version = 'Python %s\n' % sys.version.split()[0]
response = '\n'.join([message, version, uri])
return response
Next, keep in mind that Flask wants a string return type. If you want to pass a data structure back, consider jsonify.
This question already has answers here:
Get the data received in a Flask request
(23 answers)
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Store large data or a service connection per Flask session
(1 answer)
Closed 3 years ago.
I have an app that uses a variable to to locate a row in a pandas dataframe. I want the user to use the input[type=range] in html to select a year that will be used as the variable x.
Here is my python file:
from flask import Flask, render_template, request
app = Flask(__name__)
x = '2005'
mask = (df['start'] < x) & (df['end'] > x)
output = df.loc[mask]
#app.route("/")
def home():
return render_template("index.html", output=output)
Here is my html form:
<form name="myform" method="POST">
<input type="range" name="yearInputName" id="yearInputId" value="1980" min="1880" max="2010">
</form>
How do I assign the variable x to the output of the form? So when a user selects the year 2007 for example, in the python file the variable x will change to '2007'?
Use request.form.get() to access data from a form with method POST.
Something like:
from flask import Flask, render_template, request
app = Flask(__name__)
def calculate(year):
mask = (df['start'] < x) & (df['end'] > year)
return df.loc[mask]
#app.route("/", mothods=['POST', 'GET'])
def home():
try:
input_year = request.form.get('yearInputName')
except:
input_year = '2005' # Default
# You may wish to add some validation for input_year here.
output = calculate(input_year)
return render_template("index.html", output=output)
If I understood you correctly, you basically want to change the actual python file base on the user input. Probably not. Because multiple users will have separate input.
Here's the things you might want(or might help you) regardless of what I understood.
To get the input from a post request -
Simply use request.form.get('name') to get the data.
Furthermore here.
You might want to use JavaScript to send post data.
Try this-
var element = document.getElementById('yearInputId')
var xhr = new XMLHttpRequest()
xhr.open('/url') \\the route you want this data to handle
xhr.setRequestHeader('Content-type', 'application/x-www-form-urlencoded')
xhr.send("year=" + element.value)
You may want to store the year in a database or session variable
See using db with flask & using sessions
Storing in a session variable might do the work if you don't want to store the year but just as temporally.
If you want to serve '/' based on the post request
#check if request method is post
if request.method == 'POST':
year = request.form.get('year') #change year to your html post variable name
return render_template("index.html", output=year)
else if request.method == 'GET':
return render_template("index.html", output=output)
and yes, make sure to enable post request in the route.
#app.route('/', mothods=['POST', 'GET'])
Advices -
You probably want to make a separate route for the post data to process.
Use database or sessions depending on your goal. When serving future requests, just the parse the year. You may need to store a unique identifier. Like username or browser cookie along with the year.
Use JavaScript if you're updating something just locally.
The app is loading the "links_submit.html" which has a field where you can write a link, like for example (www.google.com) and you submit it, then the app is receiving this URL as HTTP Post and redirecting to another page "post_response.html" which contains a simple html for feedback with the word "Ok". Then I want to do a process with this link (crawl google and search for a specific thing) and after finish this process, automatically redirect from the "post_reponse.html" to another page to show the results I have extracted from google. Now I'm not sure how say to my app on flask: "Ok now lets use a normal function (not route) like for example:
def loadpage(link_sent_by_the_http post):
res = requests.get('www.google.com')
Imagine that after load the page I also extract some html tag on google and after finish this process I want to redirect the page "post_respose.html" with the "ok" to a new html page which contains the html tag extracted from google.
Please note I know how to load the page google and extract what I want, but I don't know how to insert this function/process in the middle of Flask and then redirect from a normal html with "ok" for a new route with the results I have extracted.
import requests
from flask import Flask, render_template, request, url_for
app = Flask(__name__)
#app.route('/test')
def form():
return render_template('links_submit.html')
#app.route('/links/', methods=['POST'])
def links():
links=request.form['links']
return render_template('post_response.html')
Intern Process (Load the received link > Extract what I want)
and then redirect the "post_response.html" to another "html" which will
contain the results that I have extracted)
if __name__ == '__main__':
app.run(debug=True)
Two ways to do it-
Create a python file say webfunctions.py and put your function in this file.
e.g. -
def inc(x):
return int(x) + 1
Now in your flask app file, you can import the whole file or just the function-
from webfunctions import inc
#app.route('/whatsnext/', methods=['POST'])
def waiting():
curVal=request.form['x']
nextVal = inc(curVal)
return render_template('post_response.html', nextVal=nextVal)
or else, you may declare your definitions at the top of your flask app file. Like below -
import requests
from flask import Flask, render_template, request, url_for
def inc(x):
return int(x) + 1
#app.route('/whatsnext/', methods=['POST'])
def waiting():
curVal=request.form['x']
nextVal = inc(curVal)
return render_template('post_response.html', nextVal=nextVal)
I'm trying to get multiple arguments from a url in Flask. After reading this SO answer I thought I could do it like this:
#app.route('/api/v1/getQ/', methods=['GET'])
def getQ(request):
print request.args.get('a')
print request.args.get('b')
return "lalala"
But when I visit /api/v1/getQ/a=1&b=2, I get a TypeError: getQ() takes exactly 1 argument (0 given). I tried other urls, like /api/v1/getQ/?a=1&b=2 and /api/v1/getQ?a=1&b=2, but to no avail.
Does anybody know what I'm doing wrong here? All tips are welcome!
You misread the error message; the exception is about how getQ is called with python arguments, not how many URL parameters you added to invoke the view.
Flask views don't take request as a function argument, but use it as a global context instead. Remove request from the function signature:
from flask import request
#app.route('/api/v1/getQ/', methods=['GET'])
def getQ():
print request.args.get('a')
print request.args.get('b')
return "lalala"
Your syntax to access URL parameters is otherwise perfectly correct. Note that methods=['GET'] is the default for routes, you can leave that off.
You can try this to get multiple arguments from a url in Flask:
--- curl request---
curl -i "localhost:5000/api/foo/?a=hello&b=world"
--- flask server---
from flask import Flask, request
app = Flask(__name__)
#app.route('/api/foo/', methods=['GET'])
def foo():
bar = request.args.to_dict()
print bar
return 'success', 200
if __name__ == '__main__':
app.run(debug=True)
---print bar---
{'a': u'hello', 'b': u'world'}
P.S. Don't omit double quotation(" ") with curl option, or it not work in Linux cuz "&"
similar question Multiple parameters in in Flask approute