Send variables from Python Flask to HTML - python

I have following Problem:
i want to send some data to Html from Python with button Click in HTML, but wenn i click the button it doesn't work at all.
Here is my code:
*
python.py:
from flask import Flask, render_template, flash, Markup, request
app = Flask(__name__)
#app.route('/')
def index():
return render_template('new.html')
#app.route('/SomeFunction', methods = ['POST', 'GET'])
def SomeFunction():
if request.method == 'GET':
text = 'Name'
print("result:")
return render_template("new.html",text = text)
if __name__ == '__main__':
app.run()
and here is my Html:
<!doctype html>
<html>
<head>
<title>The jQuery Example</title>
<div class="flashes">
{% for message in get_flashed_messages()%}
{{ message }}
{% endfor %}
</div>
<h2>jQuery-AJAX in FLASK. Execute function on button click</h2>
<script type="text/javascript" {{ url_for('static', filename='app.js')}}></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"> </script>
<script type=text/javascript> $(function() { $("#mybutton").click(function (event) { $.getJSON('/SomeFunction', { }, function(data) { }); return false; }); }); </script>
</head>
<body>
<input type = "button" id = "mybutton" value = "Click Here" />
<p>text: {{text}}</p>
</body>
</html>
So what i want is when i press the input button it will show the name what is in python defined. Maybe there are other ways what can make it works, but i need exactly in python.

Okay so passing variables from python flask to html is easy.
Import json
make a dictionary object with key whatever you want and assign your variable to that key
jobj = { 'name' : name }
Now dump this object as json and pass as argument
return render_template('htmlfile.html', res=json.dumps(jobj))
Now you would be able to access the res json in JavaScript in htmlfile.html
<Script>
var res = JSON.parse(' {{ res | safe }} ');
console.log(res.name);
</Script>

Related

Problem with updating an already updated html dom with Flask

I have a flask dropzone to upload files.
Once an upload is done I want to print a log text on the html site
It works so far, the only problem is - the div tag doesn't update the log text after the second upload. The website stays with the text from the first upload.
index.html:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script>
$(function(){
window.setInterval(function() {
loadNewLogger()
}, 500)
function loadNewLogger(){
$.ajax({
url:"/write_log",
type: "POST",
datatype: "json",
success: function(data){
$(logger).replaceWith(data)
}
});
}
});
</script>
<body>
<div style="color:rgb(0, 0, 0);text-align:center">
CDR PIPELINE </div>
{{ dropzone.create(action='upload') }}
{{ dropzone.load_js() }}
{{ dropzone.config() }}
<div id="logger">
{{ logger }}
</div>
</body>
</html>
logger.html (otherwise I would render index.html twice)
<div id="logger">
{{ logger }}
</div>
excerpt from flask_app.py:
#app.route('/',methods=['POST','GET'])
def upload():
if request.method == 'POST':
f = request.files.get('file')
f.save(os.path.join(app.config['UPLOADED_PATH'],f.filename))
upload.logger = ""
es.main()
upload.logger = es.main.result
return upload.logger
return render_template('index.html')
#app.route('/write_log',methods=['POST'])
def log():
logger = upload.logger
return jsonify('', render_template('logger.html', logger=logger))
Why is it updating the text from upload.logger only once?
First of all, instead of JQuery AJAX, I would recommend using PHP. For example, when you upload files from index.html you can redirect to upload.php, and you can display the message using "echo"
But even if you aren't comfortable with that, don't get too much into Python or JQuery. Your problem can very easily be solved with plain JavaScript:
Here is your html element in logger.html:
<div id="logger"></div>
In flask app.py:
document.getElementById("logger").innerHTML="Your message to be displayed"
I would also recommend you to remove setinterval in index.html as people don't like dynamically reloading blocks

Don't display a button while file don't exists on server - with Flask

Is it possible to show a download button only after the file is created by my Flask application?
Using PHP, it would probably be something like this:
<style>
.hidden{ display:none;}
</style>
<?php
if(!file_exists("path") ){ $class = "hidden" }
echo "<button type=\"submit\" onclick=\"window.open(\'file.txt\')\">Download!</button>";
?>
I tried to use Python code directly in the HTML file:
{% if os.path.isfile('file.txt') %}
<button type="submit" onclick="window.open('file.txt')">Download!</button>
{% else %}
<button type="submit" class="hidden" onclick="window.open('file.doc')">Download!</button>
{% endif %}
But got an error:
jinja2.exceptions.UndefinedError: 'os' is undefined
UPDATE
Full code after #furas reply.
What the code should be doing:
Creates a new thread, that will write a file.
The template is rendered, with a hidden download button.
The file is created
The download button became automatically visible - because now the file exists.
However, in the code below, the button keeps hidden after the file is written. The button only shows up if the page is reloaded after the creation of the file.
app.py
from flask import Flask, render_template
import threading
import time
import os
global exporting_threads
class ExportingThread(threading.Thread):
def run(self):
time.sleep(1)
file = open("file.txt", "w")
file.close()
app = Flask(__name__)
app.debug = True
#app.route('/')
def index():
exporting_threads = ExportingThread()
exporting_threads.start()
return render_template('index.html', file_exist = os.path.isfile('file.txt'))
if __name__ == '__main__':
app.run()
index.html, inside the 'templates' folder.
<!DOCTYPE html>
<html>
<head>
<style>
.hidden{ display:none;}
</style>
</head>
<body>
{% if file_exist %}
<button type="submit" onclick="window.open('file.doc')">Download!</button>
{% else %}
<button type="submit" class="hidden" onclick="window.open('file.doc')">Download!</button>
{% endif %}
</body>
</html>
PHP mix code with HTML and it makes big mess. But Flask tries to keep it separated.
Check if file exits in code before you render template and send only result to template - ie.
return render_string(...., file_exist=os.path.isfile('file.txt'))
and in template
{% if file_exist %}
EDIT:
Usually files are in subfolders and you should use
os.path.isfile('subfolder/file.txt')
or even
os.path.isfile('/full/path/to/file.txt')
EDIT:
Problem is more complex. Server needs longer time to create file in separated thread so this file doesn't exist yet when server check isfile(). It needs JavaScript and AJAX which will periodically send requests to other function (ie. /check) and it will send True or False from isfile().
Minimal working example using pure JavaScript and XMLHttpRequest but you can try to write it with fetch() or using library jQuery
from flask import Flask, render_template_string
import threading
import time
import os
# delete only for test code
#if os.path.isfile('file.txt'):
# os.unlink("file.txt")
class ExportingThread(threading.Thread):
def run(self):
time.sleep(5)
file = open("file.txt", "w")
file.close()
app = Flask(__name__)
app.debug = True
#app.route('/')
def index():
exporting_threads = ExportingThread()
exporting_threads.start()
return render_template_string('''<!DOCTYPE html>
<html>
<head>
<style>
.hidden {display:none;}
</style>
</head>
<body>
<button id="button" type="submit" class="hidden" onclick="window.open('file.doc')">Download!</button>
<script>
// ask server if file exists
function check() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
console.log(this.responseText);
if(this.responseText == 'True') {
// show button
document.getElementById("button").classList.remove("hidden");
// stop checking
clearTimeout(timer);
}
}
};
xhttp.open("GET", "/check", true);
xhttp.send();
}
// repeate function `check` every 1000ms (1s)
var timer = setInterval(check, 1000);
</script>
</body>
</html>''')
#app.route('/check')
def check():
return str(os.path.isfile('file.txt'))
if __name__ == '__main__':
app.run()

simple flask app server passing data with ajax and jquery

I've spent all day tinkering with this app trying to get some simple information passed to the back end of the application. I am using a simple flask app and trying to send data from a search query to the back end using ajax. However, I have been completely unsuccessful. Any help would be greatly appreciated.
Below is app.py
from scraper import scrape
from flask import Flask, render_template, jsonify, make_response, request
import json
app = Flask(__name__)
#app.route("/")
def index():
entries = json.dumps(scrape("video games"))
return render_template('index.html', entries= entries)
#app.route('/parse_data', methods=['GET', 'POST'])
def parse_data():
if request.method == "GET":
#data = request.form("blah")
#print("blah")
search = request.json
#new_search = json.dumps(scrape(data))
return search
return render_template('index.html')
if __name__ == "__main__":
app.run(debug=True, host='0.0.0.0', port=5000)
and index.html
<!DOCTYPE html>
<html>
<head>
<title>Flask app</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
</head>
<body>
<div class="topnav">
<a class="active" href="#home">Home</a>
About
Contact
<form name = "textbox" id = "textbox">
<input id ="textbox" name="textbox" type="text" placeholder="Search..">
<button type="submit">submit</button>
</form>
</div>
<p>you searched: {{search}} </p>
<div id="div1">
<p id="p1"></p>
<p id="p2"></p>
</div>
<script>
var value = $('.textbox').val();
//alert(value);
$.ajax({
type: 'POST',
url: "/parse_data",
data: JSON.stringify(value)
contentType: 'application/json',
success: function(data){
alert("success")
}
});
var jsonz = {{ entries|tojson }};
var s = JSON.parse(jsonz);
var i;
for (i = 0; i < s.length; i++) {
var para = document.createElement("p");
var node = document.createTextNode(s[i].product_name + "\n" + s[i].product_link);
para.appendChild(node);
var element = document.getElementById("div1");
element.appendChild(para);
}
//document.getElementById("user").innerHTML =
//obj;
//"Name: " + obj.product_name + "<br>" +
//"Location: " + obj.product_link;
</script>
</body>
</html>
Your code snippet has a few issues, mostly:
Your AJAX request is not bind to the button click event, so clicking the button does nothing.
You have two html elements with the same id textbox, id are supposed to be unique.
To get an html element by id use "#textbox"
On the server side (Flask):
Use the function get_json() of the request
To process the POST request you need to check for POST not GET
Try wrapping your POST request like this:
$("button").click(function (e) {
e.preventDefault();
var value = $("#textbox").val();
alert(value);
$.ajax({
type: "POST",
url: "parse_data",
data: JSON.stringify({ "text" : value } ),
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (data) {
alert(JSON.stringify(data));
}
});
});
Also remove the duplicate ids textbox, change the id of the form to something like textbox-form, finally change your parse_data function to something like this:
#app.route('/parse_data', methods=['GET', 'POST'])
def parse_data():
if request.method == 'POST':
search = request.get_json()
return jsonify(search)
return render_template('index.html')

Flask - Toggle button with dynamic label

I am new to Flask and want to create a On/Off toggle button on my website. I was wondering if and how this is possible also including a dynamic label. The following picture shows what I have in mind:
I was thinking about using a wtfforms SubmitField but I don't quite know how to implement this dynamic behavior between my routes.py file and my html template. I was thinking something like this:
forms.py:
from flask_wtf import FlaskForm
from wtforms import SubmitField
class PowerSwitchForm(FlaskForm):
power_switch = SubmitField("ON")
routes.py:
from flask import render_template, flash, redirect, url_for
from app import app
from app.forms import PowerSwitchForm
#app.route('/power', methods=['GET', 'POST'])
def power():
power_switch = PowerSwitchForm()
if power_switch.power_switch.label.text == "ON" and power_switch.validate():
flash("Power has been turned ON")
power_switch.power_switch.label.text = "OFF"
return redirect(url_for('power')
elif power_switch.power_switch.label.text == "OFF" and power_switch.validate():
flash("Power has been turned OFF")
power_switch.power_switch.label.text = "ON"
return redirect(url_for('power')
return render_template('power.html', form0=power_switch)
power.html:
<!DOCTYPE html>
{% extends "base.html" %}
{% block content %}
<h2>Power switch</h2>
<form action="" method="post" novalidate>
{{ form0.hidden_tag() }}
{{ form0.power_switch() }}
</form>
{% endblock %}
You can use jquery to handle the desired operation when the toggle button is clicked. Also, if there is a backend process that should be performed when the button is toggled, ajax can be used. This answer demonstrates both. bootstrap-toggle is a library that enables simple implementation of a toggle. To use, copy the header tag values below:
Simple toggle that displays "toggled" or "untoggled":
<html>
<body>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"></script>
<link href="https://gitcdn.github.io/bootstrap-toggle/2.2.2/css/bootstrap-toggle.min.css" rel="stylesheet">
<script src="https://gitcdn.github.io/bootstrap-toggle/2.2.2/js/bootstrap-toggle.min.js"></script>
</head>
<input type="checkbox" class='toggle' checked data-toggle="toggle">
<div class='status'>Toggled</div>
</body>
<script>
$(document).ready(function() {
$('.toggle').click(function() {
var current_status = $('.status').text();
if (current_status === 'Untoggled'){
$('.status').html('Toggled');
}
else{
$('.status').html('Untoggled');
}
});
});
</script>
</html>
Toggle that triggers backend script for both "toggled" or "untoggled":
In the template, slightly change the script:
<script>
$(document).ready(function() {
$('.toggle').click(function() {
var current_status = $('.status').text();
$.ajax({
url: "/get_toggled_status",
type: "get",
data: {status: current_status},
success: function(response) {
$(".status").html(response);
},
error: function(xhr) {
//Do Something to handle error
}
});
});
});
</script>
Then, in your app, create a route /get_toggled_status:
#app.route('/get_toggled_status')
def toggled_status():
current_status = flask.request.args.get('status')
return 'Toggled' if current_status == 'Untoggled' else 'Untoggled'
This example does the same thing as the pure html/jquery solution, however, it does demonstrate how the backend can be communicated with when using the toggle.
I am also new to Flask. And here is the pure python code with flask that I've tried.
Looks it work.
in templates/demo.html :
{% extends "bootstrap/base.html" %}
{% import "bootstrap/wtf.html" as wtf %}
{% block content %}
<div class="page-header">
{{ wtf.quick_form(form) }}
</div>
{% endblock %}
in demo.py :
from flask import Flask, render_template, redirect, url_for
from flask_bootstrap import Bootstrap
from flask_wtf import FlaskForm
from wtforms import SubmitField
class PowerState(FlaskForm) :
state = SubmitField('OFF')
app = Flask(__name__)
Bootstrap(app)
app.config['SECRET_KEY'] = 'YOUR SECRET KEY'
#app.route('/', methods=['GET', 'POST'])
def home() :
form = PowerState()
if form.validate_on_submit() :
if form.state.label.text == 'OFF' :
PowerState.state = SubmitField('ON')
elif form.state.label.text == 'ON' :
PowerState.state = SubmitField('OFF')
return redirect(url_for('home'))
return render_template('demo.html', form=form)
then run :
flask run
Regards, Alex.Wu

Django and Ajax

Im trying to get a basic app working in Django that incorporates AJAX.
The app will take a domain name and will then send it to the server, which will do a dns lookup on it and then send the response back via AJAX to the client.
Views
from django.http import *
from django.shortcuts import render_to_response
from django.template import RequestContext
import sys
import os
import socket
def main(request):
if request.method == 'POST':
dig_input = request.POST['digInput']
digoutput = socket.gethostbyname(dig_input)
return render_to_response('digajax.html', {'response': digoutput}, context_instance=RequestContext(request))
else:
return render_to_response('digajax.html', context_instance=RequestContext(request))
URLs
url(r'^digajax$', 'digajax.views.main'),
Templates
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<script type='text/javascript' src='http://code.jquery.com/jquery-1.8.2.js'></script>
<script type="text/javascript">
function send_request(){
$.get(location.href, function(data){
$("#output").html(data.output);
});
}
</head>
<body>
<form method="post" name="diginput form" action="/digajax">
{% csrf_token %}
<input name="digInput" id="digInput" type="text">
<input type="button" onclick="send_request();" value="Request this page with AJAX">lookup</input>
</form>
{% if response %}
<div id="output">
<p>{{ response|linebreaksbr }}</p>
</div>
{% else %}
<p>no</p>
{% endif %}
</body}
</html>
Without AJAX everything is working. Now that I want to use AJAX Im not what what code I should add to each section.
Any help would be really appreciated...............
Django provides an method on the request object your view is passed which will tell you whether the request was made via XmlHttp, request.is_ajax().
If that method returns true, you probably want to return only the fragment of the page you want to update, instead of the whole page.
If that method returns false, you probably want to return the entire page, since the user either has JavaScript turned off, or there was some type of error which caused the view to be requested normally.
So, your view should look like:
def main(request):
if request.method == 'POST':
dig_input = request.POST['digInput']
digoutput = socket.gethostbyname(dig_input)
if request.is_ajax():
return HttpResponse("<p>%s</p>" % digoutput)
else:
return render(request, 'digajax.html', {
'response': digoutput
})
else:
return render(request, 'digajax.html')
Your JavaScript code should be look like:
<script type="text/javascript">
function send_request(){
$.get(location.href, function(data){
$("#output").html(data);
});
}
</script>

Categories