Flask route to download .xml files leading to 404 Not Found - python

I have a flask (0.10.1) app running on a Debian Jessie VPS and powered by nginx (1.6.2). The app is working fine but I have a problem on a specific route I added recently.
The route is intended for downloading .xml files.
It is dynamic to tell the directory and the file name:
#app.route('/backups/<dir_key>/<filename>')
And it registers a function based on the flask send_from_directory function:
def backups(dir_key,filename):
directory = os.path.join(app.config['BACKUPXML_FOLDER'], dir_key)
return send_from_directory(directory, filename, as_attachment=True)
The route is generated thanks to the flask url_for function, and returned to the frontend:
return jsonify({
'backupFileUrl': url_for('backups', dir_key=dir_key, filename = filename, _external=True)
})
where it is stored in an AngularJS variable:
$scope.backupFileUrl = response.backupFileUrl;
And finally included in a <a> tag for download :
<a class="btn btn-primary"
ng-show="sessionDownload"
ng-href="{{ backupFileUrl }}" target="_blank">
<span class="glyphicon glyphicon-save"></span> Télécharger </a>
But when I click on the button, I get the following error :
What is weird to is that :
The download is properly triggered when the app is powered by a small Python server on a local Windows machine.
I have a route intended for downloads of .xlsx files which is actually working, and both on a local Windows machine and on the Jessie VPS.
Someone see how I can define the route to make it work ?
Here is the api architecture if needed :
api/app.py
import sys
sys.path.append('../')
from flask_script import Server, Manager
from kosapp import app, db
manager = Manager(app)
if __name__ == '__main__':
manager.run()
api/config.py
from os.path import abspath, dirname, join
import tempfile
basedir = dirname(abspath(__file__))
BASEDIR = dirname(abspath(__file__))
DEBUG = True
REPORTS_FOLDER = '/tmp/reports'
# on local machine
# REPORTS_FOLDER = os.path.join(tempfile.gettempdir(), 'reports')
BACKUPXML_FOLDER = '/tmp/backups'
# on local machine
# BACKUPXML_FOLDER = os.path.join(tempfile.gettempdir(), 'backups')
api/kosapp/__init__.py
from flask import Flask
app = Flask(__name__)
app.url_map.strict_slashes = False
app.config.from_object('config')
from kosapp import views
api/kosapp/views.py
import os
from flask import send_file, jsonify, request, render_template, send_from_directory
from kosapp import app
#app.route('/reports/<dir_key>/<filename>')
def reports(dir_key, filename):
directory = os.path.join(app.config['REPORTS_FOLDER'], dir_key)
return send_from_directory(directory, filename)
#app.route('/backups/<dir_key>/<filename>')
def backups(dir_key,filename):
directory = os.path.join(app.config['BACKUPXML_FOLDER'], dir_key)
return send_from_directory(directory, filename, as_attachment=True)
As a note, the route '/reports/<dir_key>/<filename>' is intended for downloading .xlsx file and works fine.

Did you remember to reload the app on the server? That's usually the problem if i get different results on my development computer and the web server.
For instance, if you deployed with gunicorn, you would have to restart gunicorn so the server would know about the changes to your code.

Related

Host a web app locally with Windows 10 using Flask and Python with one line of code

I have built a web app using flask and I won't be able to host it in a cloud server for the moment. I want to host it in my Windows 10 OS, and I'm not concerned about the app to have secure certificates since it is intended to be shown as prototype. Three files are enough to showcase the result of the app:
myapp.py:
# This a Natural Language Processing app using a machine learning model
class Lingus:
def __init__(self, data):
self.text = data
def output(self):
return self.text+" - "+self.text+"\n"+self.text
Next, is an html file in the folder templates templates/my-form.html:
<form method="POST">
<input name="text">
<input type="submit">
</form>
Finally, a python script using flask for the app called main.py:
from flask import Flask, request, render_template
from myapp import Lingus
app = Flask(__name__)
#app.route('/')
def my_form():
return render_template('my-form.html')
#app.route('/', methods=['POST'])
def my_form_post():
text = request.form['text']
processed_text = text.upper()
result = Ling(text)
return result.output()
if __name__ == "__main__":
app.run(debug=True)
Again, the goal is to make this app accessible through any browser in the web (not locally), using Windows 10. I don't have experience in back-end development or network engineering but I think this is something which is technically possible.
PS: I don't need the app to have security certificates for clients.
v25 Solution in the question's comment worked perfectly. It avoided port forwarding, and it consisted of downloading ngrok and writing one line of code for the app to be hosted locally. You only have to download ngrok on a free account, and write ngrok http < PORT ON WHICH YOUR APP IS RUNNING >. I was running my flask app on the port 5000, so for my case, I did run the app locally, opened ngrok.exe and wrote:
ngrok http 5000
And that's it. Now, I can show my app's prototype to anyone and give it for users to test it. However, the app address changes every 8 hours, you should upgrade your account to get a static address for your app.

PythonAnywhere and Flask app keep returning error code

trying to host my flask app (run.py) on PythonAnywhere. Have my virtualenv setup and all of my modules imported via pip. The flask app is stored at this location:
/home/goldsilvermonitor/GSM/run.py
Set up my WSGI file and it keeps giving my the error:
TypeError: 'module' object is not callable
My flask file look like this: (run.py)
from flask import Flask, flash, redirect, render_template, request, session, abort, url_for
app = Flask(__name__)
# ./Home Script:
#app.route("/")
#app.route("/index")
def index():
return render_template('index.html')
# ./Disclaimer Page:
#app.route("/disclaimer")
def disclaimer():
return render_template('disclaimer.html')
# ./data.xml:
app.route("/dataxml")
def dataxml():
return render_template('data.xml')
# ./404 Page
#app.errorhandler(404)
def page_not_found(e):
# 404 status set explicitly
return render_template('404.html'), 404
# FLask Debug Script:s
if __name__ == "__main__":
app.run(host="0.0.0.0", port='5000', debug=True)
And my WSGI file looks like this:
# +++++++++++ FLASK +++++++++++
# Flask works like any other WSGI-compatible framework, we just need
# to import the application. Often Flask apps are called "app" so we
# may need to rename it during the import:
#
#
import sys
#
## The "/home/goldsilvermonitor" below specifies your home
## directory -- the rest should be the directory you uploaded your Flask
## code to underneath the home directory. So if you just ran
## "git clone git#github.com/myusername/myproject.git"
## ...or uploaded files to the directory "myproject", then you should
## specify "/home/goldsilvermonitor/myproject"
path = '/home/goldsilvermonitor/GSM'
if path not in sys.path:
sys.path.append(path)
#
import run as application # noqa
#
# NB -- many Flask guides suggest you use a file called run.py; that's
# not necessary on PythonAnywhere. And you should make sure your code
# does *not* invoke the flask development server with app.run(), as it
# will prevent your wsgi file from working.
I have no idea what is causing this error. Have tried reuploading the files, redoing the WSGI config. But to no avail. If someone could help me then that would be great! Also should I remove the debug=true from the flask file before I go live?
You're trying to import a module (the file run.py) and then use it as an application; the application is the app object in that file, so in the WSGI file you should replace this:
import run as application # noqa
...with this:
from run import app as application # noqa

Flask send_file is sending old file instead of newest

I have a flask app where using one Flask route the server creates a csv file and saves it to the server. Using a generated button on the client page, another Flask route is triggered to get the most recent file, move it to a tmp folder and send that file to the user using send_file.
Right now, when I run the process the first time and download the file, all works as expected. However, the second time I run the process, it serves me the old CSV instead of the newly generated one. This continues until I hit the refresh button on my browser.
The following is my app code:
from flask import Flask, render_template, flash, redirect, request, url_for, Response, send_file
import os
import time
import shutil
import glob
app = Flask(__name__)
app.config['SECRET_KEY'] = 'secret!'
#app.route('/')
def index():
return render_template('index.html')
#app.route('/downloadcsv')
def downloadcsv():
current = os.getcwd()
try:
list = glob.glob('{}/*.csv'.format(current))
except:
print('No file found')
basename = os.path.basename(os.path.normpath(max(list, key=os.path.getctime)))
shutil.move(basename, './tmp/{}'.format(basename))
return send_file('./tmp/{}'.format(basename), as_attachment=True)
In case it is needed, the following is the JS code which "generates" the download button:
var download = '<div id="downloadsection" class="container-contact100-form-btn"><button id="download" class="contact100-form-btn"> <span>DOWNLOAD CSV</span></button></div>';
Please also let me know if I am over complicating the download process...
Thanks!!
send_file has a caching timeout that you are not configuring. It will send the same file that has been cached unless you tell it not to cache the file like so:
send_file('./tmp/{}'.format(basename), as_attachment=True, cache_timeout=0)
See the following references for more information:
http://flask.pocoo.org/docs/1.0/api/#flask.send_file
http://flask.pocoo.org/docs/1.0/api/#flask.Flask.get_send_file_max_age
http://flask.pocoo.org/docs/1.0/config/#SEND_FILE_MAX_AGE_DEFAULT
#ritlew pretty much answers the question, to add to his answer, After adding cache_timeout=0, clear the browser cache and hit the URL in incognito mode.
You can also try:
Disabling caching in Flask

No response from a Flask application using Apache server

I have created a flask application and am hosting it on a Ubuntu server. I know that my apache config is correct since I am able serve the example flask application. However, this one seems to be giving me trouble. The code is below:
from flask import Flask, render_template, request, url_for
import pickle
import engine
import config
# Initialize the Flask application
app = Flask(__name__)
model = pickle.load(open(config.MODEL_PATH, "rb"))
collection = engine.Collection(config.DATABASE_PATH)
search_engine = engine.SearchEngine(model, collection)
#app.route('/')
def form():
return render_template('index.html')
#app.route('/search/', methods=['POST'])
def search():
query = request.form['query']
results = search_engine.query(query)
return render_template('form_action.html', query=query, results=results)
#app.route('/retrieve/<int:item_number>', methods=['GET'])
def retrieve(item_number):
item = engine.Product(item_number, collection.open_document(str(item_number)))
return render_template('document.html', item=item)
if __name__ == '__main__':
app.run()
When running the file directly through the python interpreter, it works fine and I can access. However, when starting through apache and wsgi, I get no response from the server. It just hangs when making a request and nothing is available on the logs.
I suspect that my issue may have something to do with the three objects I initialize at the beginning of the program. Perhaps it gets stuck running those?
Update: I have tried commenting out certain parts of the code to see what is causing it to stall. Tracing it out to the engine module, importing NearestNeighbors seems to be causing the issue.
import sqlite3
import config
from sklearn.neighbors import NearestNeighbors
from preprocessor import preprocess_document
from collections import namedtuple

Trouble Hosting flask app on pythonanywhere

I am a first time user of pythonanywhere
I first started by doing a git clone of my code from github through the bash console. I did not use a virtual environment. My WSGI app was invoked in my app.py file. Also, my code uses sqlalchemy to interact with my database.
Basically, the flask app was like a custom api that returned JSON for GET and POST requests and I am having trouble viewing the JSON output. I am not sure what exactly I am doing wrong or missing.
Code in app.py file:
#!flask/bin/python
from flask import Flask
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy_declarative import Base, Quote
from flask import request
from flask import abort
import json
#connect to database
engine = create_engine("sqlite:///quotes.db")
Base.metadata.bind = engine
DBSession = sessionmaker(bind=engine)
session = DBSession()
app = Flask(__name__)
#app.route("/trumptext/api/quotes", methods=["GET"])
def get_quotes():
quoteList = session.query(Quote).all()
result = []
for q in quoteList:
my_dict = {}
my_dict["id"] = q.id
my_dict["quote"] = q.quote
result.append(my_dict)
return json.dumps(result,ensure_ascii=False).encode('utf8')
#app.route("/trumptext/api/quotes", methods=["POST"])
def add_quote():
if not request.json or not "quote" in request.json:
abort(400)
new_quote = request.json["quote"]
q = Quote(quote=new_quote)
session.add(q)
session.commit()
quoteList = session.query(Quote).all()
last = quoteList[-1]
result = []
my_dict = {}
my_dict["id"] = last.id
my_dict["quote"] = last.quote
result.append(my_dict)
return json.dumps(result,ensure_ascii=False).encode('utf8'), 201
if __name__ == "__main__":
app.run()
Also, code in /var/www/nnelson_pythonanywhere_com_wsgi.py:
import os
import sys
path = '/home/nnelson/trumptextapi'
if path not in sys.path:
sys.path.append(path)
from app import app as application
If I enter something like :
http://nnelson.pythonanywhere.com/trumptext/api/quotes (to perform a GET request)
It should ideally return all the quotes stored in the quotes.db database in JSON format, however all I get it output that looks like this: [] I tested my code on localhost using the curl tool and it works just fine. I am having trouble hosting it though
Any help is appreciated.
You're using a relative path to your database, so it's probably looking at a database that you don't expect. Use a full path to the database or make it relative to the path of your app.py file so that you know where it's getting the database from.

Categories

Resources