When I run the following code snippet, I get a URL not found error. Does anyone know what is wrong with it? Thanks.
from flask import *
app = Flask(__name__)
app.route('/set')
def setcookie():
res = make_response("<h2>The cookie is set</h2>")
res.set_cookie('framework', 'flask')
return res
if __name__=="__main__":
app.run(debug=True)
Add an # to your app.route like below:
#app.route('/set')
def setcookie():
res = make_response("<h2>The cookie is set</h2>")
res.set_cookie('framework', 'flask')
return res
Related
I have a function called getTableData() which runs another function get_table() and based on that get_table() output final function is called which renders a template and also routes to a different page.
So the problem is its not routing to a different url (/tabdata) from get_final() function
Flask code:
#app.route('/api/getTableData', methods=['POST'])
def getTableData():
value = request.json['value']
value=value[:8]
url="https://some.com"+value
df_time=get_table(url)
return get_final(df_time)
def get_table(url):
driver = webdriver.Chrome(options=options)
driver.get(url)
abv = pd.read_html(driver.find_element(By.ID,"frm_hist").get_attribute('outerHTML'))[0]
df_time = pd.DataFrame(abv)
return df_time
#app.route("/tabdata")
def get_final(df_time):
return render_template("new.html",df_time = df_time)
Code Explanation:
I am using the value from value variable then concat 2 strings to make the url and then passing the url to another function named get_table() which goes to that url and webscrapes the table and converts it into python dataframe.
So using the returned python dataframe get_final() is called to render the template in a html file and also route to the /tabdata url. Everything is working well except the page is not routing to that url
You have to return a redirect:
from flask import redirect
#app.route("/tabdata/<df_time>")
def get_final(df_time):
return redirect("http://www.example.com", code=200)
Use redirect and use it with url_for in case you decide to change your routes in the future. You also need to change your view function get_final
from flask import redirect, url_for
#app.route('/api/getTableData', methods=['POST'])
def getTableData():
value = request.json['value']
value = value[:8]
url = "https://some.com"+value
df_time = get_table(url)
return redirect(url_for('get_final', df_time=df_time))
def get_table(url):
driver = webdriver.Chrome(options=options)
driver.get(url)
abv = pd.read_html(driver.find_element(By.ID,"frm_hist").get_attribute('outerHTML'))[0]
df_time = pd.DataFrame(abv)
return df_time
#app.route("/tabdata/<df_time>") # notice change here!
def get_final(df_time):
return render_template("new.html", df_time=df_time)
In getTableData(), change
return get_final(df_time)
to
return redirect(url_for("get_final", df_time=df_time))
In get_final(), change
#app.route("/tabdata")
def get_final(df_time):
return render_template("new.html",df_time = df_time)
to
#app.route("/tabdata/<df_time>")
def get_final(df_time):
return render_template("new.html", df_time=df_time)
Although your redirected URL will look something like this; "http://localhost/tabdata/16606505". If this is not preferred, you can always redirect for GET request with query parameters (which will look like this; "http://localhost/tabdata&data=16606505") or redirect for POST request which will not show the df_time parameter in browser history.
I'm making a doc to pdf converter program, and i have occured an error as below:
Im an begginer in programming and i dont know how to fix it, below i paste python code:
from flask import Flask
from flask import request, render_template, redirect, url_for, send_file
import os
from typing import Tuple
from docx2pdf import convert
#from tkinter import Tk,messagebox
#from tkinter import _tkinter
UPLOADER_FOLDER = ''
app = Flask(__name__)
app.config['UPLOADER_FOLDER'] = UPLOADER_FOLDER
#app.route('/')
#app.route('/index', methods=['GET', 'POST'])
def index():
if request.method == "POST":
def docx2pdf(input_file: str, output_file: str, pages: Tuple = None):
if pages:
pages = [int(i) for i in list(pages) if i.isnumeric()]
result = convert(docx_file=input_file, pdf_file=output_file, pages=pages)
summary = {
"File": input_file, "Pages": str(pages), "Output File": output_file
}
print("\n".join("{}:{}".format(i, j) for i, j in summary.items()))
return result
file = request.files['filename']
if file.filename!= '':
file.save(os.path.join(app.config['UPLOADER_FOLDER'], file.filename))
input_file = file.filename
output_file = r"hello.pdf"
docx2pdf(input_file, output_file)
pdf = input_file.split(".")[0]+".pdf"
print(pdf)
lis=pdf.replace(" ", "=")
return render_template("docx.html", variable=lis)
return render_template("index.html")
#app.route('/docx', methods=['GET', 'POST'])
def docx():
if request.method=="POST":
lis = request.form.get('filename', None)
lis = lis.replace("=", " ")
return send_file(lis, as_attachment=True)
return render_template("index.html")
if __name__=="__main__":
app.debug = True
app.run()
There are two templates called index.html and docx.html in Templates directory, this is how it looks in Pycharm:
Does anyone have an idea where i made an mistake? Thanks
You are passing parameters into the convert method like this:
result = convert(docx_file=input_file, pdf_file=output_file, pages=pages)
But the docx2pdf convert method is defined like this:
def convert(input_path, output_path=None, keep_active=False):
as you can see, there is no parameter called docx_file, so you get the error that this parameter was unexpected. To fix this, either get rid of the names altogether:
result = convert(input_file, output_file)
or use the correct parameter names:
result = convert(input_path=input_file, output_path=output_file)
I also see that you have passed a variable called pages. I'm not familiar with this library so I can't be 100% sure, but I didn't find a convert function with a parameter called pages anywhere.
Since you are in PyCharm, right click on the convert function and select Go to -> Declaration to see the method. You should be able to see what the function does. There is limited documentation on this library so you will have to rely on reading the code to understand.
This question already has an answer here:
Capture arbitrary path in Flask route
(1 answer)
Closed 1 year ago.
I am trying to pass a website as a parameter. It works if the website does not have a "/" in it. For example: http://192.168.1.156:2434/www.cookinglight.com scrapes cooking light for all the images on it's page; however, if I pass in http://192.168.1.156:2434/https://www.cookinglight.com/recipes/chicken-apple-butternut-squash-soup then an I get an invalid response. Here is my current code:
import json
from flask import Flask, render_template
from imagescraper import image_scraper
app = Flask(__name__)
#app.route("/", methods = ['GET'])
def home():
return render_template('index.html')
#app.route("/<site>", methods = ['GET'])
def get_image(site):
return json.dumps(image_scraper(site))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=2434, debug=True)
import requests
from bs4 import BeautifulSoup
def image_scraper(site):
"""scrapes user inputed url for all images on a website and
:param http url ex. https://www.cookinglight.com
:return dictionary key:alt text; value: source link"""
search = site.strip()
search = search.replace(' ', '+')
website = 'https://' + search
response = requests.get(website)
soup = BeautifulSoup(response.text, 'html.parser')
img_tags = soup.find_all('img')
# create dictionary to add image alt tag and source link
images = {}
for img in img_tags:
try:
name = img['alt']
link = img['src']
images[name] = link
except:
pass
return images
I tried urrllib but did not have any success. Any help would be greatly appreciated! I am a student so still learning!!
UPDATE:
I believe this is the issue as described in the stackoverflow post
Need to allow encoded slashes on Apache
Flask uses / as separate between arguments in url - so you can create route("/<arg1>/<arg2>/<arg3>") (or popular in blogs route("/<year>/<month>/<day>")) and you can get values in variables arg1, arg2, arg3 - and when you try to use your url with / then it also treat it as "/<arg1>/<arg2>/<arg3>" and it tries to find route like route("/<arg1>/<arg2>/<arg3>") and it can't find it and it gives error 404.
route("/<site>") can match only string without /. site is only variable name - it doesn't mean that it will treat it as url with /
If you want to use / as part of single argument, not as separator between arguments, then you need <path:site>.
from flask import Flask
app = Flask(__name__)
#app.route("/")
def home():
return "Hello World"
#app.route("/<path:site>")
def get_image(site):
return f"OK: {site}"
if __name__ == '__main__':
app.run(host='0.0.0.0', port=2434)#, debug=True)
See also Variable Rules
EDIT:
It has nothing to do with issue. Flask was specially created to use / as special char to separate values.
I am building my first API in Flask. It shall receive json string from Postman and according to the log in terminal POST request is working, I can see my json string in line 15 in the code print(json_).
However next line is a problem:
query = pd.read_json(json_, orient='index')
This line shall convert json into pd dataframe, so I can convert it to an numpy array and load it into my machine learning model.
Outside of Flask my logic work well, but here code gots broken. I put several print command to trace the code breaking point and it seems to me this query line.
Any suggestions are very much appreciated. Thank you in advance!
Vlad
The complete code for API looks like this:
from flask import Flask, request, jsonify
import joblib
import traceback
import pandas as pd
import numpy as np
app = Flask(__name__)
#app.route('/predict', methods=['POST'])
def predict():
try:
json_ = request.json
print(json_)
query = pd.read_json(json_, orient='index')
print('query', query)
res = np.array(query).reshape(1,-1)
print('results', res)
prediction = rf.predict(res)
print(prediction)
return jsonify({'prediction': list(prediction)})
except:
return jsonify({'trace': traceback.format_exc()})
if __name__ == '__main__':
try:
port = int(sys.argv[1])
except:
port = 12345
rf = joblib.load('random_forest_model_diabetes_refined_31_5_2021.pkl') # Load ML model
print ('Model loaded')
app.run(debug=True, port=port)
When I replaced my query line
query = pd.read_json(json_, orient='index')
with:
query = pd.json_normalize(json_)
It works. I am puzzled.
I'm writing a script to collect the emails of those users that didn't receive an email confirmation email and resend it to them. The script works obviously outside of flask app context. I would like to use url_for() but can't get it right.
def resend(self, csv_path):
self.ctx.push()
with open(csv_path) as csv_file:
csv_reader = csv.reader(csv_file)
for row in csv_reader:
email = row[0]
url_token = AccountAdmin.generate_confirmation_token(email)
confirm_url = url_for('confirm_email', token=url_token, _external=True)
...
self.ctx.pop()
The first thing I had to do was to set SERVER_NAME in config. But then I get this error message:
werkzeug.routing.BuildError: Could not build url for endpoint
'confirm_email' with values ['token']. Did you mean 'static' instead?
This is how it's defined, but I don't think it can even find this, because it's not registered when ran as script:
app.add_url_rule('/v5/confirm_email/<token>', view_func=ConfirmEmailV5.as_view('confirm_email'))
Is there a way to salvage url_for() or do I have to build my own url?
Thanks
It is much easier and proper to get the URL from the application context.
You can either import the application and manually push context with app_context
https://flask.palletsprojects.com/en/2.0.x/appcontext/#manually-push-a-context
from flask import url_for
from whereyoudefineapp import application
application.config['SERVER_NAME'] = 'example.org'
with application.app_context():
url_for('yourblueprint.yourpage')
Or you can redefine your application and register the wanted blueprint.
from flask import Flask, url_for
from whereyoudefineyourblueprint import myblueprint
application = Flask(__name__)
application.config['SERVER_NAME'] = 'example.org'
application.register_blueprint(myblueprint)
with application.app_context():
url_for('myblueprint.mypage')
We can also imagine different ways to do it without the application, but I don't see any adequate / proper solution.
Despite everything, I will still suggest this dirty solution.
Let's say you have the following blueprint with the following routes inside routes.py.
from flask import Blueprint
frontend = Blueprint('frontend', __name__)
#frontend.route('/mypage')
def mypage():
return 'Hello'
#frontend.route('/some/other/page')
def someotherpage():
return 'Hi'
#frontend.route('/wow/<a>')
def wow(a):
return f'Hi {a}'
You could use the library inspect to get the source code and then parse it in order to build the URL.
import inspect
import re
BASE_URL = "https://example.org"
class FailToGetUrlException(Exception):
pass
def get_url(function, complete_url=True):
source = inspect.getsource(function)
lines = source.split("\n")
for line in lines:
r = re.match(r'^\#[a-zA-Z]+\.route\((["\'])([^\'"]+)\1', line)
if r:
if complete_url:
return BASE_URL + r.group(2)
else:
return r.group(2)
raise FailToGetUrlException
from routes import *
print(get_url(mypage))
print(get_url(someotherpage))
print(get_url(wow).replace('<a>', '456'))
Output:
https://example.org/mypage
https://example.org/some/other/page
https://example.org/wow/456