So this is embarrassing. I've got an application that I threw together in Flask and for now it is just serving up a single static HTML page with some links to CSS and JS. And I can't find where in the documentation Flask describes returning static files. Yes, I could use render_template but I know the data is not templatized. I'd have thought send_file or url_for was the right thing, but I could not get those to work. In the meantime, I am opening the files, reading content, and rigging up a Response with appropriate mimetype:
import os.path
from flask import Flask, Response
app = Flask(__name__)
app.config.from_object(__name__)
def root_dir(): # pragma: no cover
return os.path.abspath(os.path.dirname(__file__))
def get_file(filename): # pragma: no cover
try:
src = os.path.join(root_dir(), filename)
# Figure out how flask returns static files
# Tried:
# - render_template
# - send_file
# This should not be so non-obvious
return open(src).read()
except IOError as exc:
return str(exc)
#app.route('/', methods=['GET'])
def metrics(): # pragma: no cover
content = get_file('jenkins_analytics.html')
return Response(content, mimetype="text/html")
#app.route('/', defaults={'path': ''})
#app.route('/<path:path>')
def get_resource(path): # pragma: no cover
mimetypes = {
".css": "text/css",
".html": "text/html",
".js": "application/javascript",
}
complete_path = os.path.join(root_dir(), path)
ext = os.path.splitext(path)[1]
mimetype = mimetypes.get(ext, "text/html")
content = get_file(complete_path)
return Response(content, mimetype=mimetype)
if __name__ == '__main__': # pragma: no cover
app.run(port=80)
Someone want to give a code sample or url for this? I know this is going to be dead simple.
In production, configure the HTTP server (Nginx, Apache, etc.) in front of your application to serve requests to /static from the static folder. A dedicated web server is very good at serving static files efficiently, although you probably won't notice a difference compared to Flask at low volumes.
Flask automatically creates a /static/<path:filename> route that will serve any filename under the static folder next to the Python module that defines your Flask app. Use url_for to link to static files: url_for('static', filename='js/analytics.js')
You can also use send_from_directory to serve files from a directory in your own route. This takes a base directory and a path, and ensures that the path is contained in the directory, which makes it safe to accept user-provided paths. This can be useful in cases where you want to check something before serving the file, such as if the logged in user has permission.
from flask import send_from_directory
#app.route('/reports/<path:path>')
def send_report(path):
return send_from_directory('reports', path)
Do not use send_file or send_static_file with a user-supplied path. This will expose you to directory traversal attacks. send_from_directory was designed to safely handle user-supplied paths under a known directory, and will raise an error if the path attempts to escape the directory.
If you are generating a file in memory without writing it to the filesystem, you can pass a BytesIO object to send_file to serve it like a file. You'll need to pass other arguments to send_file in this case since it can't infer things like the file name or content type.
If you just want to move the location of your static files, then the simplest method is to declare the paths in the constructor. In the example below, I have moved my templates and static files into a sub-folder called web.
app = Flask(__name__,
static_url_path='',
static_folder='web/static',
template_folder='web/templates')
static_url_path='' removes any preceding path from the URL (i.e.
the default /static).
static_folder='web/static' to serve any files found in the folder
web/static as static files.
template_folder='web/templates' similarly, this changes the
templates folder.
Using this method, the following URL will return a CSS file:
<link rel="stylesheet" type="text/css" href="/css/bootstrap.min.css">
And finally, here's a snap of the folder structure, where flask_server.py is the Flask instance:
You can also, and this is my favorite, set a folder as static path so that the files inside are reachable for everyone.
app = Flask(__name__, static_url_path='/static')
With that set you can use the standard HTML:
<link rel="stylesheet" type="text/css" href="/static/style.css">
I'm sure you'll find what you need there: http://flask.pocoo.org/docs/quickstart/#static-files
Basically you just need a "static" folder at the root of your package, and then you can use url_for('static', filename='foo.bar') or directly link to your files with http://example.com/static/foo.bar.
EDIT: As suggested in the comments you could directly use the '/static/foo.bar' URL path BUT url_for() overhead (performance wise) is quite low, and using it means that you'll be able to easily customise the behaviour afterwards (change the folder, change the URL path, move your static files to S3, etc).
You can use this function :
send_static_file(filename)
Function used internally to send static
files from the static folder to the browser.
app = Flask(__name__)
#app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
What I use (and it's been working great) is a "templates" directory and a "static" directory. I place all my .html files/Flask templates inside the templates directory, and static contains CSS/JS. render_template works fine for generic html files to my knowledge, regardless of the extent at which you used Flask's templating syntax. Below is a sample call in my views.py file.
#app.route('/projects')
def projects():
return render_template("projects.html", title = 'Projects')
Just make sure you use url_for() when you do want to reference some static file in the separate static directory. You'll probably end up doing this anyways in your CSS/JS file links in html. For instance...
<script src="{{ url_for('static', filename='styles/dist/js/bootstrap.js') }}"></script>
Here's a link to the "canonical" informal Flask tutorial - lots of great tips in here to help you hit the ground running.
http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-i-hello-world
A simplest working example based on the other answers is the following:
from flask import Flask, request
app = Flask(__name__, static_url_path='')
#app.route('/index/')
def root():
return app.send_static_file('index.html')
if __name__ == '__main__':
app.run(debug=True)
With the HTML called index.html:
<!DOCTYPE html>
<html>
<head>
<title>Hello World!</title>
</head>
<body>
<div>
<p>
This is a test.
</p>
</div>
</body>
</html>
IMPORTANT: And index.html is in a folder called static, meaning <projectpath> has the .py file, and <projectpath>\static has the html file.
If you want the server to be visible on the network, use app.run(debug=True, host='0.0.0.0')
EDIT: For showing all files in the folder if requested, use this
#app.route('/<path:path>')
def static_file(path):
return app.send_static_file(path)
Which is essentially BlackMamba's answer, so give them an upvote.
For angular+boilerplate flow which creates next folders tree:
backend/
|
|------ui/
| |------------------build/ <--'static' folder, constructed by Grunt
| |--<proj |----vendors/ <-- angular.js and others here
| |-- folders> |----src/ <-- your js
| |----index.html <-- your SPA entrypoint
|------<proj
|------ folders>
|
|------view.py <-- Flask app here
I use following solution:
...
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "ui", "build")
#app.route('/<path:path>', methods=['GET'])
def static_proxy(path):
return send_from_directory(root, path)
#app.route('/', methods=['GET'])
def redirect_to_index():
return send_from_directory(root, 'index.html')
...
It helps to redefine 'static' folder to custom.
app = Flask(__name__, static_folder="your path to static")
If you have templates in your root directory, placing the app=Flask(name) will work if the file that contains this also is in the same location, if this file is in another location, you will have to specify the template location to enable Flask to point to the location
So I got things working (based on #user1671599 answer) and wanted to share it with you guys.
(I hope I'm doing it right since it's my first app in Python)
I did this -
Project structure:
server.py:
from server.AppStarter import AppStarter
import os
static_folder_root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "client")
app = AppStarter()
app.register_routes_to_resources(static_folder_root)
app.run(__name__)
AppStarter.py:
from flask import Flask, send_from_directory
from flask_restful import Api, Resource
from server.ApiResources.TodoList import TodoList
from server.ApiResources.Todo import Todo
class AppStarter(Resource):
def __init__(self):
self._static_files_root_folder_path = '' # Default is current folder
self._app = Flask(__name__) # , static_folder='client', static_url_path='')
self._api = Api(self._app)
def _register_static_server(self, static_files_root_folder_path):
self._static_files_root_folder_path = static_files_root_folder_path
self._app.add_url_rule('/<path:file_relative_path_to_root>', 'serve_page', self._serve_page, methods=['GET'])
self._app.add_url_rule('/', 'index', self._goto_index, methods=['GET'])
def register_routes_to_resources(self, static_files_root_folder_path):
self._register_static_server(static_files_root_folder_path)
self._api.add_resource(TodoList, '/todos')
self._api.add_resource(Todo, '/todos/<todo_id>')
def _goto_index(self):
return self._serve_page("index.html")
def _serve_page(self, file_relative_path_to_root):
return send_from_directory(self._static_files_root_folder_path, file_relative_path_to_root)
def run(self, module_name):
if module_name == '__main__':
self._app.run(debug=True)
By default folder named "static" contains all static files
Here's a code sample:
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
Use redirect and url_for
from flask import redirect, url_for
#app.route('/', methods=['GET'])
def metrics():
return redirect(url_for('static', filename='jenkins_analytics.html'))
This servers all files (css & js...) referenced in your html.
One of the simple way to do. Cheers!
demo.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template("index.html")
if __name__ == '__main__':
app.run(debug = True)
Now create folder name called templates.
Add your index.html file inside of templates folder
index.html
<!DOCTYPE html>
<html>
<head>
<title>Python Web Application</title>
</head>
<body>
<div>
<p>
Welcomes You!!
</p>
</div>
</body>
</html>
Project Structure
-demo.py
-templates/index.html
The issue I had was related to index.html files not being served for directories when using static_url_path and static_folder.
Here's my solution:
import os
from flask import Flask, send_from_directory
from flask.helpers import safe_join
app = Flask(__name__)
static = safe_join(os.path.dirname(__file__), 'static')
#app.route('/')
def _home():
return send_from_directory(static, 'index.html')
#app.route('/<path:path>')
def _static(path):
if os.path.isdir(safe_join(static, path)):
path = os.path.join(path, 'index.html')
return send_from_directory(static, path)
Thought of sharing.... this example.
from flask import Flask
app = Flask(__name__)
#app.route('/loading/')
def hello_world():
data = open('sample.html').read()
return data
if __name__ == '__main__':
app.run(host='0.0.0.0')
This works better and simple.
All the answers are good but what worked well for me is just using the simple function send_file from Flask. This works well when you just need to send an html file as response when host:port/ApiName will show the output of the file in browser
#app.route('/ApiName')
def ApiFunc():
try:
return send_file('some-other-directory-than-root/your-file.extension')
except Exception as e:
logging.info(e.args[0])```
The simplest way is create a static folder inside the main project folder. Static folder containing .css files.
main folder
/Main Folder
/Main Folder/templates/foo.html
/Main Folder/static/foo.css
/Main Folder/application.py(flask script)
Image of main folder containing static and templates folders and flask script
flask
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def login():
return render_template("login.html")
html (layout)
<!DOCTYPE html>
<html>
<head>
<title>Project(1)</title>
<link rel="stylesheet" href="/static/styles.css">
</head>
<body>
<header>
<div class="container">
<nav>
<a class="title" href="">Kamook</a>
<a class="text" href="">Sign Up</a>
<a class="text" href="">Log In</a>
</nav>
</div>
</header>
{% block body %}
{% endblock %}
</body>
</html>
html
{% extends "layout.html" %}
{% block body %}
<div class="col">
<input type="text" name="username" placeholder="Username" required>
<input type="password" name="password" placeholder="Password" required>
<input type="submit" value="Login">
</div>
{% endblock %}
The URL for a static file can be created using the static endpoint as following:
url_for('static', filename = 'name_of_file')
<link rel="stylesheet" href="{{url_for('static', filename='borders.css')}}" />
By default, flask use a "templates" folder to contain all your template files(any plain-text file, but usually .html or some kind of template language such as jinja2 ) & a "static" folder to contain all your static files(i.e. .js .css and your images).
In your routes, u can use render_template() to render a template file (as I say above, by default it is placed in the templates folder) as the response for your request. And in the template file (it's usually a .html-like file), u may use some .js and/or `.css' files, so I guess your question is how u link these static files to the current template file.
If you are just trying to open a file, you could use app.open_resource(). So reading a file would look something like
with app.open_resource('/static/path/yourfile'):
#code to read the file and do something
In the static directory, create templates directory inside that directory add all the html file create separate directory for css and javascript as flask will treat or recognize all the html files which are inside the template directory.
static -
|_ templates
|_ css
|_javascript
|_images
This is what worked for me:
import os
from flask import Flask, render_template, send_from_directory
app = Flask(__name__)
root = os.path.join(os.path.dirname(os.path.abspath(__file__)), "whereyourfilesare")
#app.route('/', methods=['GET'])
def main(request):
path = request.path
if (path == '/'):
return send_from_directory(root, 'index.html')
else:
return send_from_directory(root, path[1:])
In my case, i needed all the files from a static folder to be accessible by the user, as well as i needed to use templates for some of my html files, so that common html code could be placed in the template and code gets reused. Here is how i achieved both of them together:
from flask import Flask, request, render_template
from flask.json import JSONEncoder
app = Flask(__name__, template_folder='static')
#app.route('/<path:path>')
def serve_static_file(path):
# In my case, only html files are having the template code inside them, like include.
if path.endswith('.html'):
return render_template(path)
# Serve all other files from the static folder directly.
return app.send_static_file(path)
And all of my files are kept under static folder, which is parallel to main flask file.
For example, to return an Adsense file I have used:
#app.route('/ads.txt')
def send_adstxt():
return send_from_directory(app.static_folder, 'ads.txt')
Related
This question already has answers here:
Return a download and rendered page in one Flask response
(2 answers)
Closed 6 months ago.
I have this flask app route:
#app.route('/generatecleanbudgetfile', methods=['GET', 'POST'])
def clean_budget():
file = request.files.get('data_file')
app.logger.info('Budget Formatting request has started')
try:
if request.method == 'POST':
file = request.files.get('data_file')
file.seek(0)
buffer = budget_cleaner(file)
buffer.seek(0)
app.logger.info('Conversion Complete')
return send_file(
buffer,
as_attachment=True,
attachment_filename=f'stripped_budget_{dt.today().strftime("%m.%d.%Y")}.xlsx',
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
except:
app.logger.error(f"Budget formatting failed on {file}")
return render_template('error_type.html', title='Unable to process uploaded budget')
My html:
{% extends "base.html" %}
{% block head %}
{% endblock %}
{% block content %}
<div id="vo_budget_file_settings">
{# Upload Final CRO Budget File #}
<p id="uploadPara">Please upload the final CRO budget File</p>
<form class="" action="/generatecleanbudgetfile" method=POST enctype=multipart/form-data>
<input type="file" name="data_file" accept=".xls, .xlsx, .xlsm"/>
<input type="submit" value="Begin Format" onclick="loading();"/>
</form>
</div>
<!-- funtion to show css spinner on button click -->
<script type="text/javascript">
function loading(){
$(".loader").show();
}
</script>
I understand that flask cannot both render_template and send_file since it can only return a single item.
Question:
How would I go about downloading a file via JavaScript instead so I could use my return to render a new template?
I'm wanting to replace this piece:
return send_file(
buffer,
as_attachment=True,
attachment_filename=f'stripped_budget_{dt.today().strftime("%m.%d.%Y")}.xlsx',
mimetype='application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
)
To download the file with JS, you could encode it and include it in your template as a string literal inside a JS Blob object, then save that Blob as soon as the page renders. Something like this in your template for success, where you pass your encoded file contents into the file_contents template variable:
<body>
Page content here
<script>
const myBlob = new Blob(["{{file_contents}}"], {type:"your-file's-mime-type"})
// then google "how to save js blob to local file".
// This other post might help: https://stackoverflow.com/questions/25547475/save-to-local-file-from-blob
</script>
</body>
To further illustrate as an example, making a blob that has the plaintext contents "Hello World" would go like new Blob(["Hello World"], {type:"text/plain"}). Your case might be more complicated if you file type isn't plaintext or has a weird encoding, but this is the general idea.
Another (probably less hack-y) idea would be do the same Blob thing except use JS's native fetch API to get the file contents from your server to the Blob instead of passing it through the template. This is similar to the other answer that suggested saving the file on the server, except instead of providing an a tag you just do the download in pure JS.
Flask can't do both things(render & send file) in a single request.
But you can have an alternative solution↓
In your generatecleanbudgetfile request:
Generate a file and save it in server
Provide a file link in your html
just render_template in this request
So, when the user get the response, they can click on download link to retrieve the file generated in the first step.
I want to make a variable with Python, and then console.log() the variable in JavaScript. I know how to access the variable in JavaScript, but I don't know how to make the Python script run when the page is loaded. How can I do this?
Unlike Javascript, you can't run Python directly in the browser. You would need Python to run server-side. A possible alternative may be to use transcrypt to generate javascript equivalents of Python for a frontend-only solution.
For instance, transcrypt allows you to "import" python modules into JavaScript. Here, a python script called hello.py is "imported" into the context and can be called form javascript like hello.solarSystem.greet()
<script type="module">import * as hello from './__target__/hello.js'; window.hello = hello;</script>
<h2>Hello demo</h2>
<p>
<div id = "greet">...</div>
<button onclick="hello.solarSystem.greet ()">Click me repeatedly!</button>
<p>
<div id = "explain">...</div>
<button onclick="hello.solarSystem.explain ()">And click me repeatedly too!</button>
See the transcrypt docs for more info.
Otherwise, you'd probably be running a Python webserver on the backend for this use-case. Something like flask.
from flask import Flask, render_template_string
app = Flask(__name__)
def do_something():
"""Returns an interesting value"""
return "foo"
template = """
<html>
<script>
console.log('{{ value }}')
</script>
"""
#app.route('/')
def home():
my_value = do_something()
return render_template_string(template, value=my_value)
app.run(debug=True)
I created a website with HTML/CSS. I also used Javascript for events (click on button, ...).
Now I want to connect a Python script with it and more importantly, return the results from my Python functions to my website and display (use) them there.
Consider something like this: I have a website with an input field and a button. If you click on the button, a Python script should run which returns if the input is an odd or even number (of course you don't need Python for this specific case, but that's what I want to do).
From my research I believe Flask is the library to be used for this, but I really don't know how to do it. I found very few examples. I would really appreciate if someone could implement the above example or tell me how to do it exactly.
I know there are already some questions about that concept here online, but as I said, with very few examples.
You're right about Flask being a good solution for this and there are examples and tutorials everywhere. If what you want is just to run a specific function on a button press and get something back in javascript, I've put a quick example is below.
# app.py
from flask import Flask, render_template
from flask import jsonify
app = Flask(__name__)
# Display your index page
#app.route("/")
def index():
return render_template('index.html')
# A function to add two numbers
#app.route("/add")
def add():
a = request.args.get('a')
b = request.args.get('b')
return jsonify({"result": a+b})
if __name__ == "__main__":
app.run(host='0.0.0.0', port=80)
This can then be run with python app.py and make sure your index.html is in the same directory. Then you should be able to go to http://127.0.0.1/ and see your page load.
This implements a function which adds two numbers, this can be called in your javascript by calling http://127.0.0.1/add?a=10&b=20. This should then return {"result": 30}.
You can grab this in your javascript using the code below and place this code in your buttons on click callback.
let first = 10;
let second = 20;
fetch('http://127.0.0.1/add?a='+first+'&b='+second)
.then((response) => {
return response.json();
})
.then((myJson) => {
console.log("When I add "+first+" and "+second+" I get: " + myJson.result);
});
This should be the barebone basics, but once you can submit data to Flask and get data back, you now have an interface to run things in Python.
Edit: Full Front-end example
https://jsfiddle.net/4bv805L6/
I really appreciate time spent on this answer. But the answer did not help me in the way I needed it. At that point I had no clue what to do, but since thenbI figured it out some time ago and I thought I should share my solution here:
That's app.py:
from flask import Flask, render_template, request
app = Flask(__name__)
#app.route('/stick', methods=['GET', 'POST'])
def stick():
if request.method == 'POST':
result = request.form['string1'] + request.form['string2']
return render_template('index.html', result=result)
else:
return render_template('index.html')
if __name__ == "__main__":
app.run()
And that's index.html (put in the folder templates):
<!DOCTYPE html>
<html>
<body>
<h3> Stick two strings </h3>
<form action="{{ url_for('stick') }}" method="post">
<input type="text" name="string1">
<input type="text" name="string2">
<input type="submit" value="Go!">
<p id="result"></p>
</form>
<script>
document.getElementById("result").innerHTML = "{{result}}"
</script>
</body>
</html>
In the terminal, type in python app.py and it should work.
I am using Dropzone.js to allow drag and drop upload of CSV files via a Flask web site. The upload process works great. I save the uploaded file to my specified folder and can then use df.to_html() to convert the dataframe into HTML code, which I then pass to my template. It gets to that point in the code, but it doesn't render the template and no errors are thrown. So my question is why is Dropzone.js preventing the render from happening?
I have also tried just return the HTML code from the table and not using render_template, but this also does not work.
init.py
import os
from flask import Flask, render_template, request
import pandas as pd
app = Flask(__name__)
# get the current folder
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
#app.route('/')
def index():
return render_template('upload1.html')
#app.route('/upload', methods=['POST'])
def upload():
# set the target save path
target = os.path.join(APP_ROOT, 'uploads/')
# loop over files since we allow multiple files
for file in request.files.getlist("file"):
# get the filename
filename = file.filename
# combine filename and path
destination = "/".join([target, filename])
# save the file
file.save(destination)
#upload the file
df = pd.read_csv(destination)
table += df.to_html()
return render_template('complete.html', table=table)
if __name__ == '__main__':
app.run(port=4555, debug=True)
upload1.html
<!DOCTYPE html>
<meta charset="utf-8">
<script src="https://rawgit.com/enyo/dropzone/master/dist/dropzone.js"></script>
<link rel="stylesheet" href="https://rawgit.com/enyo/dropzone/master/dist/dropzone.css">
<table width="500">
<tr>
<td>
<form action="{{ url_for('upload') }}", method="POST" class="dropzone"></form>
</td>
</tr>
</table>
EDIT
Here is the sample csv data I am uploading:
Person,Count
A,10
B,12
C,13
Complete.html
<html>
<body>
{{table | safe }}
</body>
</html>
Update: Now you can use Flask-Dropzone, a Flask extension that integrates Dropzone.js with Flask. For this issue, you can set DROPZONE_REDIRECT_VIEW to the view you want to redirect when uploading complete.
Dropzone.js use AJAX to post data, that's why it will not give back the control to your view function.
There are two methods to redirect (or render template) when all files were complete uploading.
You can add a button to redirect.
Upload Complete
You can add an event listener to automatic redirect page (use jQuery).
<script>
Dropzone.autoDiscover = false;
$(function() {
var myDropzone = new Dropzone("#my-dropzone");
myDropzone.on("queuecomplete", function(file) {
// Called when all files in the queue finish uploading.
window.location = "{{ url_for('upload') }}";
});
})
</script>
In view function, add an if statement to check whether the HTTP method was POST:
import os
from flask import Flask, render_template, request
app = Flask(__name__)
app.config['UPLOADED_PATH'] = 'the/path/to/upload'
#app.route('/')
def index():
# render upload page
return render_template('index.html')
#app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
for f in request.files.getlist('file'):
f.save(os.path.join('the/path/to/upload', f.filename))
return render_template('your template to render')
Your code does work. Your template will be rendered and returned.
Dropzone will upload files you drag and drop into your browser 'in the background'.
It will consume the response from the server and leave the page as is. It uses the response from the server to know if the upload was successful.
To see this in action:
Navigate to your page
Open up your favourite browser dev tools; (in firefox press CTRL+SHIFT+K)
Select the network tab
Drag your csv into the dropzone pane and note that the request shows in the dev tools network table
Here is a screen shot from my browser. I copied your code as is from your question.
To actually see the rendered complete.html you will need to add another flask endpoint and have a way to navigate to that.
For example:
in upload1.html add:
Click here when you have finished uploading
in init.py change and add:
def upload():
...
# you do not need to read_csv in upload()
#upload the file
#df = pd.read_csv(destination)
#table += df.to_html()
return "OK"
# simply returning HTTP 200 is enough for dropzone to treat it as successful
# return render_template('complete.html', table=table)
# add the new upload_complete endpoint
# this is for example only, it is not suitable for production use
#app.route('/upload-complete')
def upload_complete():
target = os.path.join(APP_ROOT, 'uploads/')
table=""
for file_name in os.listdir(target):
df = pd.read_csv(file_name)
table += df.to_html()
return render_template('complete.html', table=table)
If you are using Flask-Dropzone then:
{{ dropzone.config(redirect_url=url_for('endpoint',foo=bar)) }}
I'm hacking a cms-like system that use Jinja2 and Javascript in frontend and Python in backend.
I implemented some Python functions on backend that do stuff on database.
I want to launch that functions from HTML pages, so i used Jinja2.
The problem is that the snippets {% %} and {{ }} are always parsed and processed when HTML is loaded.
I want to execute that functions when I click a button or a link.
How could I make it works?
Jinja2 is a template engine. You are wrong about its use.
You could create a small app in some lightweight web framework, like Flask or Bottle, and route some ajax routes to expected methods.
Here is an example using Flask:
backend.py
import os
from json import dumps
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def index():
return render_template('cmd.html')
#app.route("/cmd")
def cmd():
osname = os.uname()[3]
print(osname)
return dumps({'name': osname})
if __name__ == "__main__":
app.run()
As described in docs, templates must be in a folder called template inside the project folder.
cmd.html
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.3/jquery.min.js"></script>
<script type="text/javascript">
function cmd(){
$.ajax({
type: "GET",
url: "http://0.0.0.0:5000/cmd",
success: function (data) {
$("#result").html("dfsdfds")
},
});
}
</script>
</head>
<body>
Item
<div id="result"></div>
</body>
</html>
To execute it just run python backend.py. Open your browser and go to http://127.0.0.1:500
The app runs a command on backend and returns the result.