Flask app to download Excel files from directory - python

I am building an app to download a bunch of Excel files from a file directory. This question/answer got me started, but the latest version of Flask doesn't appear to work quite the same way. I followed these instructions to build the app so far, but I'm not quite following how to link to files in a directory for download. Do you have any advice or can you point me in a different direction?
Thanks in advance.
#app.py:
from flask
import Flask, render_template
from waitress import serve
from flask import url_for
from config import directory_to_folder
filename = "static/Test1.xlsx"
#app.route("/")
def index():
return render_template('index.html')
def download_file(filename):
return send_from_directory(directory_to_folder, filename, as_attachment=True)
if name == "main":serve(app, host='localhost', port=int("5000"))
#index.html:
{% extends 'base.html' %}
{% block content %}
{% block title %} Welcome Home {% endblock %}
<table>
<tr>
<th>Test File</th>
</tr>
<tr>
<td>{{url_for('static', filename='Test2.xlsx')}}</td>
</tr>
</table>
{% endblock %}
In my flaskapp directory, I have the files:
app.py
\>templates
\>>base.html
\>>index.html
\>static
\>>css
\>>Test1.xlsx
Best,
John

Related

How to execute python code on client side using flask?

I have my server.py file, where i have:
from flask import Flask,render_template,url_for
app=Flask(__name__)
#app.route("/")
#app.route("/home")
def home():
return render_template("home.html",posts=posts,title="arroz")
if __name__=="__main__":
app.run(debug=False)
My home.html file has:
{%extends "layout.html"%}
{%block content%}
<!--here-->
{%endblock content%}
I want to execute some python code in a python file on the client side in the comment here on the home.html file. I can't just call regular python code from flask, because that would run on the server side. How can I run it on the client side?
My project's structure is the following:
|-server.py
|-pythonToExecuteOnClientSide.py
|-templates
|-home.html
This won't work since Python is not a web-app language supported by browsers. Everything that is client-side needs to be able to run on the client computer and for Python code you need to have Python installed on your computer.
The only option you have is to code your feature in JavaScript to let it run on the client side.
Why exactly do you want it to run on the client side? Maybe there is a different solution for your problem. Like a server-client program.
You are already executing python code on the client side.
{% pyton code %} <html> {% python %}.
to give you an example.
when you render your page you can pass a python variable named 'posts' to your page with the value "i did it"; along with a python variable named 'title' with the value "arroz".
return render_template("home.html", posts=posts, title=title)
you can display the value of those python variables like this:
{%extends "layout.html"%}
{%block content%}
{{ posts }} {{ title }}
{%endblock content%}
you can format the value displayed just like any other html content:
<p> {{ posts }} </p> <h1> {{ title }} </h1>
your final code should be
server.py
from flask import Flask,render_template,url_for
app=Flask(__name__)
#app.route("/")
#app.route("/home")
def home():
posts = None
title = "arroz"
return render_template("home.html",posts=posts,title=title)
if __name__=="__main__":
app.run(debug=False)
home.html
{%extends "layout.html"%}
{%block content%}
<p> {{ posts }} </p> <h1> {{ title }} </h1>
{%endblock content%}

Flask Application : add condition to check for environment in html template file

I am rendering an application in an <iframe> in my Flask Application.
The localhost link is http://localhost:8000/dashboard2/ and pushing this to AWS Elastic Beanstalk hosted on: http://server-name.elasticbeanstalk.com/dashboard2
My application is written in python and dashboard.html jinja template renders the application.
Contents of dashboard.html:
{% extends "base.html" %}
{% block content %}
<div class="embed-responsive embed-responsive-16by9">
<iframe loading="lazy" class="embed-responsive-item" src="http://localhost:8000/dashboard/" width="100%" height="600"></iframe>
</div>
{% endblock %}
Questions is, how can I check for environment type os and render either app on localhost or production? I'd need to do this in .html template.
Is there a way to access and print the environment in jinja template?
I would set an environment variable when running the app that specifies whether the app should be run in development or production mode:
FLASK_ENV=production flask run
Then inside your template file you can access the environment through the app's config and render different content based on the value:
<div>
{% if config["ENV"] == 'production' %}
Production content...
{% else %}
Development content...
{% endif %}
</div>

flask send_from_directory within a file representation

Hi I currently have a flask app that shows files and their details, now I want flask to also allow file downloads from the page of the represented file
I tried a couple things including send_from_directory() which didn't work. So my question is how can I add a working download link to the page?
#app.route('/browser/<path:urlFilePath>')
def browser(urlFilePath):
nestedFilePath = os.path.join(FILE_SYSTEM_ROOT, urlFilePath)
if os.path.isdir(nestedFilePath):
itemList = os.listdir(nestedFilePath)
fileProperties = {"filepath": nestedFilePath}
if not urlFilePath.startswith("/"):
urlFilePath = "/" + urlFilePath
return render_template('browse.html', urlFilePath=urlFilePath, itemList=itemList)
if os.path.isfile(nestedFilePath):
fileProperties = {"filepath": nestedFilePath}
sbuf = os.fstat(os.open(nestedFilePath, os.O_RDONLY)) #Opening the file and getting metadata
fileProperties['type'] = stat.S_IFMT(sbuf.st_mode)
fileProperties['mode'] = stat.S_IMODE(sbuf.st_mode)
fileProperties['mtime'] = sbuf.st_mtime
fileProperties['size'] = sbuf.st_size
if not urlFilePath.startswith("/"):
urlFilePath = "/" + urlFilePath
return render_template('file.html', currentFile=nestedFilePath, fileProperties=fileProperties)
return 'something bad happened'
#app.route('/downloads/<path:filename>', methods=['GET', 'POST'])
def download(filename):
uploads = os.path.join(current_app.root_path, app.config['UPLOAD_FOLDER'])
return send_from_directory(directory=uploads, filename=filename)
And with the following HTML
{% extends 'base.html' %}
{% block header %}
<h1>{% block title %}Filebrowser{% endblock %}</h1>
{% endblock %}
{% block content %}
<p>Current file: {{ currentFile }}</p>
<p>
<table>
{% for key, value in fileProperties.items() %}
<tr>
<td>{{ key }}</td>
<td>{{ value }}</td>
</tr>
<tr>
File
</tr>
{% endfor %}
</table>
</p>
{% endblock %}
I want the download link on that page to work for the {{ currentFile }} can anyone help me out?
Firstly, the link to the file in your file.html template should probably go outside the for loop -- otherwise, the link will appear multiple times which is probably not what you want.
Secondly, based on your /downloads route, your call to url_for for the download link doesn't match up. It should be:
File
You need to supply the filename as an argument so that the flask server can match it to the route & in url_for, you need to supply the name of the function - which in this case is download instead of downloads.
Lastly, your /browser route prepends the subdirectory to the filename - so when you pass currentFile to the HTML template, it will contain the directory prefix -- which you will want to strip, otherwise your link wouldn't work. The file download would then work since in your /downloads route, you prefix the filename with the directory anyway. Hence, when you render the HTML template, use os.path.basename() to obtain the filename without the directory, i.e.
return render_template('file.html', currentFile=os.path.basename(nestedFilePath), fileProperties=fileProperties)

Flask Flatpages not able to load table of contents

I made the following small website as an introduction to Flask, and already it doesn't work! It's not able to load the table-of-contents page.
My app.py, which is the server is as follows:
import os
from flask import Flask, request, render_template
from flask_flatpages import FlatPages
from Engine.nerve_net import Nerve_Tree
# Some configuration, ensures:
# 1. Pages are loaded on request.
# 2. File name extension for pages is html.
DEBUG = True
FLATPAGES_AUTO_RELOAD = DEBUG
FLATPAGES_EXTENSION = '.html'
#Instantiate the Flask app
app = Flask(__name__)
app.config.from_object(__name__)
pages = FlatPages(app)
#app.route("/")
#app.route("/index")
def index():
return render_template('index.html') #This returns the main welcome page
#app.route("/contents")
def contents():
return render_template('contents.html', pages=pages) #This returns the table of contents page
# URL Routing - Flat Pages: Retrieves the page path
#app.route("/<path:path>/")
def page(path):
page = pages.get_or_404(path)
return render_template("page.html", page=page)
if __name__ == "__main__":
app.run(debug=True)
My table of contents, the page which displays all files within the pages directory is as follows:
{% extends "tab.html" %}
{% block content %}
</br>
<h2>TABLE OF CONTENTS</h2>
<ul>
{% for page in pages %}
<li>
<a href="{{ url_for("page", page=page.path) }}">{{ page.title }}
</li>
{% else %}
<li>No pages so far</li>
{% endfor %}
</ul>
{% endblock content %}
In this example there is only one page in the pages directory named ncs1.html, which is as follows:
title: Hello
published: 2010-12-22
Hello, *World*!
Lorem ipsum dolor sit amet
Pointing the browser to my main welcome page on http://127.0.0.1:5000/ renders the page successfully. However pointing my browser to the table-of-contents-page on http://127.0.0.1:5000/contents gives the following error:
Could not build url for endpoint 'page' with values ['page']. Did you forget to specify values ['path']?
Where am I going wrong?
As the author above mentioned, changing the table-of-contents code worked:
<a href="{{ url_for('page', path=page.path) }}"

render_template HTML renders but variables not evaluated

I am trying to build an "enterprise grade" version of a flask app so am using blueprints and a fancy directory structure. I have a "toy" version of this app where everything is in a very flat directory structure with no blueprints and it works.
I have a route program that calcs some variables then passes them to render_template to generate html. The html displays in the browser but all of the variables appear to be set to NONE.
My app uses blueprints and SQLite3.
I have tried multiple things to isolate the error.
Make a textual change to html template to ensure the right template is being picked up. It is.
Pass trivial string variable to html template and see if they show up, they don't.
View source of rendered html, there is nothing where the flask variable names {{ x }} occur in the html template, including the {{ x }} text itself. So it appears the value None has been been used.
Test the code leading up to the render_template, it works perfectly.
My directory structure is: -
\myapp
app.py
\app
__init__.py
\main
__init__.py
routes.py
...
\meta
__init__.py
routes.py
...
\templates
...
base.html
index.html
The code in \meta\routes.py (which corresponds to the meta blueprint) works down to and including entitys = stmt.fetchall() and is: -
from flask import Flask, render_template, request
import sqlite3 as sql
from app.meta import bp
from app import Config
config = Config()
metafile = os.path.join(config.META_DIR, config.META_MS, config.META_DB)
#bp.route('/', methods=['GET', 'POST'])
#bp.route('/index', methods=['GET', 'POST'])
def index():
meta = sql.connect(metafile)
stmt = meta.cursor()
stmt.execute("SELECT * FROM [meta.Entity]")
entitys = stmt.fetchall()
return render_template("index.html", entitys = entitys)
In case it is relevant here is \meta\__init__.py: -
from flask import Blueprint
bp = Blueprint('meta', __name__)
The template html is as follows. The base.html is: -
<!doctype html>
<html>
<head>
{% if title %}
<title>{{ title }} - Metapplica</title>
{% else %}
<title>Metapplica</title>
{% endif %}
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="{{ url_for('static', filename = 'w3.css') }}">
<link rel="stylesheet" href="{{ url_for('static', filename = 'style.css') }}">
</head>
<body>
<div>
Home
</div>
<hr>
{% with messages = get_flashed_messages() %}
{% if messages %}
<ul>
{% for message in messages %}
<li>{{ message }}</li>
{% endfor %}
</ul>
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</body>
</html>
and index.html is: -
{% extends "base.html" %}
{% block content %}
<h2>Entities</h2>
<table border = 1>
<thead>
<td>Entity</td>
<td>Action</td>
</thead>
{% for entity in entitys %}
<tr>
<td>{{ entity["Name"] }}</td>
<td>
List
Add
</td>
</tr>
{% endfor %}
</table>
{% endblock %}
Finally the rendered html is this: -
<!doctype html>
<html>
<head>
<title>Home - Metapplica</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="/static/w3.css">
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<div>
Home
</div>
<hr>
<h2>Entities </h2>
<table border = 1>
<thead>
<td>Entity</td>
<td>Action</td>
</thead>
</table>
</body>
</html>
In response to #Tobin's comment I have included the code that (should) be registering the blueprint. I use an application factory.
Here is app\__init__()
import logging
from logging.handlers import SMTPHandler, RotatingFileHandler
import os
from flask import Flask, session, redirect, url_for, escape, request, current_app
from config import Config
def create_app(config_class=Config):
app = Flask(__name__)
app.config.from_object(config_class)
# Register blueprints
from app.errors import bp as errors_bp
app.register_blueprint(errors_bp, url_prefix='/err')
from app.auth import bp as auth_bp
app.register_blueprint(auth_bp, url_prefix='/auth')
from app.meta import bp as meta_bp
app.register_blueprint(meta_bp, url_prefix='/meta')
from app.main import bp as main_bp
app.register_blueprint(main_bp)
return app
and here is the code that calls it: -
from app import create_app
app = create_app()
I suspect that somehow when Flask renders the html template the passed variables are not available to the "flask engine" which is pointing somewhere else.
Nothing fails and there are no error messages.
What am I doing wrong?

Categories