I created an API that can get data from MySQL. It working if the stockList is defined. However, in actual world, I need to get it from the Ionic app, and the stockList is defined by individual user.
Simply put stockList =[] does not work.
Currently the flask_app.py is as below:
from flask import Flask,jsonify,abort,make_response,request
import MySQLdb
import MySQLdb.cursors
app = Flask(__name__)
#app.route('/KLSEwatch', methods=['GET'])
def KLSEwatch():
db = MySQLdb.connect(host='vinvin.mysql.pythonanywhere-services.com',user='vinvin',passwd='xxx',db='vinukdb$default',cursorclass=MySQLdb.cursors.DictCursor)
curs = db.cursor()
stockList = ['SHELL','GENM']
placeholders = ','.join(['%s'] * len(stockList))
query = 'SELECT * FROM KLSE WHERE Stock IN ({})'.format(placeholders)
curs.execute(query,tuple(stockList))
f = curs.fetchall()
return jsonify({'Stock': f})
what I shall replace stockList as it shall get the data from user, which is from an Ionic app. The data is can be string or a 4 digits numbers
Below is the code in watchlistCtrl.js in Ionic app
//setting get counter-number of get requests-
var getCounter = 0;
for (var market in watchListQuery) {
if(watchListQuery[market].length>0){
getCounter += 1;
}
}
if(getCounter == 0)
$ionicLoading.hide();
$scope.watchedStocks = [];
for (var market in watchListQuery) {
if(watchListQuery[market].length>0){
var queryString = watchListQuery[market].toString().replace(/,/g, "','");
$webServicesFactory.get($marketProvider[market].queryURL+"/watchlist_query", {AnonymousToken: $marketProvider[market].token}, {parameters:{stockList:queryString}}).then(
function success(data) {
getCounter -=1 ;
$scope.watchedStocks = $scope.watchedStocks.concat(data);
if(getCounter <= 0)
$ionicLoading.hide();
},
function error() {
$ionicLoading.hide();
}
);
}
}//end of for each loop
You didn't show us any of your Ionic code, but here's a simple example of taking input from your Ionic app and submitting it to Flask. First, some HTML for the frontend (I'm only using Angular, since that is the common theme here - the rest of Ionic isn't relevant to this problem):
<!-- templates/home.html -->
<!doctype html>
<html lang="en">
<head>
<title>Ionic / Flask</title>
</head>
<body>
<div ng-app="app">
<div ng-controller="MyCtrl">
<p>Enter a comma-separated string value, like "BAC,XYZ"</p>
<input type="text" ng-model="stockList">
<button ng-click="submit()">Submit</button>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.14/angular.js"></script>
<script>
angular.module('app', [])
.controller('MyCtrl', function ($http, $log, $scope) {
$scope.stockList = '';
$scope.submit = function () {
$http.get('/KLSEwatch', {params: {stockList: $scope.stockList}}).then(function (result) {
$log.log('This is the query to execute: ',result.data)
})
};
})
</script>
</body>
</html>
And then here's a modified version of your Flask app, to demonstrate that this will generate the correct query:
# app.py
from flask import Flask,jsonify,abort,make_response,request, render_template
import MySQLdb
import MySQLdb.cursors
app = Flask(__name__)
app.config['DEBUG'] = True
#app.route('/')
def home():
return render_template('home.html')
#app.route('/KLSEwatch', methods=['GET'])
def KLSEwatch():
stockList = request.args['stockList'].split(',')
placeholders = ','.join(['%s'] * len(stockList))
query = 'SELECT * FROM KLSE WHERE Stock IN ({})'.format(placeholders)
print('This is the query: %s' % (query % tuple(stockList)))
return query % tuple(stockList)
app.run()
All you need to do is run the app, enter a string value into the input field & submit it, and then check the results in your browser console log, or in the output for the Flask app.
Related
I have this code that is in python and randomly makes a math equation and checks the user answer for 1 minute:
import random
import time
correct=0
wrong=0
def random_problem(num_operations):
eq = str(random.randint(1, 100))
for _ in range(num_operations):
eq += random.choice(["+"])
eq += str(random.randint(1, 100))
return eq
start = time.time()
while True:
elapsed = time.time() - start
if elapsed > 60:
quotient=correct/wrong
precent=quotient*10
total_questions=correct+wrong
print(correct,"Correct",wrong,"Wrong, total questions",total_questions)
break
problem = random_problem(1)
ask=int(input(problem +": "))
solution = eval(problem)
if ask == solution:
correct=correct+1
print("Correct")
else:
wrong=wrong+1
print("Wrong, the correct answer is",solution)
I wanted to know if it is possible to make this go from the console onto a UI. I and using flask. Thanks
Flask server is good for this. This is how the code in the flask should look like:
# app.route('/', methods=['GET', 'POST'])
def home():
if request.method == "POST":
num = request.form['num']
# Check num if it is correct, use your code
# result is the data you will want to save
open_file('data.json', "w", result)
# math is your example
return render_template("index.html", math=math)
To save, I used my open_file () function, which looks like this:
def open_file(name, mode="r", data=None):
script_dir = os.path.dirname(__file__)
file_path = os.path.join(script_dir, name)
if mode == "r":
with open(file_path, mode, encoding='utf-8') as f:
data = json.load(f)
return data
elif mode == "w":
with open(file_path, mode, encoding='utf-8') as f:
json.dump(data, f)
In html, the input form should look like this:
<form method = "POST" >
<input name = "text" type = "text">
<input name = "num" type = "number">
<button> submit </button>
</form>
Your math example show like this:
<h1>{{math}}</h1>
I would probably recommend making a timer on the web in javascript, I think in flask it might not work
I used everything from my github repository: https://github.com/adammaly004/Online_fridge
I hope it will help you, Adam
It's a little hard to understand what you mean by saving the data. There are several different ways to store data. The variant to choose depends on the data and its use.
You can find data from a form in Flask in the request.form object as long as it was sent using the POST method. The name attribute of the input field determines under which you can request the data on the server.
The example below shows you a possible solution how to implement your code in Flask. It should serve as a starting point for you to develop your own solution or expand it on your own.
To avoid the eval function, a dict is used and filled with the necessary operators and functions from the operator module. The result of the generated task is then calculated and saved in the session cookie.
If the user enters a result or lets the time elapse, the input is compared with the result from the session.
The time limit is set by a JavaScript timeout, which automatically submits the form as soon as the time has elapsed.
Flask (app.py)
from flask import Flask
from flask import render_template, request, session
from operator import add, sub
import random
app = Flask(__name__)
app.secret_key = 'your secret here'
#app.route('/', methods=['GET', 'POST'])
def index():
if request.method == 'POST':
# Get the user input and convert it to an integer.
# If no entry is made, the default value 0 is returned.
r = request.form.get('r', 0, type=int)
# Check the result and choose a message depending on it.
msg = (
'Ooops, wrong result.',
'Yeah, you are right.'
)[int(r == session.get('r'))]
# This is the mapping of the operators to the associated function.
ops = { '+': add, '-': sub }
# Generate the task and save the result in the session.
op = random.choice(list(ops.keys()))
a = random.randint(1,100)
b = random.randint(1,100)
session['r'] = ops[op](a,b)
# Render the page and deliver it.
return render_template('index.html', **locals())
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
</head>
<body>
{% if msg -%}
<p>{{msg}}</p>
{% endif -%}
<form name="task" method="post">
<span>{{a}} {{op}} {{b}} = </span>
<input type="number" name="r" />
<input type="submit">
</form>
<script type="text/javascript">
(function() {
// Submit the form automatically after the time has elapsed.
setTimeout(function() {
document.querySelector('form[name="task"]').submit();
}, 10000)
})();
</script>
</body>
</html>
I am new in Flask. My goal is to generate dynamic div containers every time I upload a dxf file and next submit happens. For example: one file uploaded- one div shown; two files uploaded- two divs shown and so on.
I can convert uploaded dxf files to .png images and I would like to show these images in div elements displayed after every upload.
I use input tag to upload files (type='file') and Java Script to generate dynamic elements (divs and their child tags).
The problem is that every time I upload file, the template is loading again and no new content is shown except the image of the last uploaded dxf. Please, give me a piece of advice to solve it.
HTML
...
<form enctype="multipart/form-data" id="uploadForm" action="/upload_files" name="uploadForm" method="post">
DXF file: <input type="file" id="dxfUpload" onchange="form.submit(); createConfigure();" name="dxfUpload" />
<div id="calcHolder" name="calcHolder">
<script type="text/javascript">
function createConfigure() {
var div = document.createElement("div");
div.id = "dxf-"+Math.random() * 100000000000000000 + "-"
+ window.performance.now() * 100000000000000000;
id_div=div.id;
div.className = 'border pad';
div.style.width = "640px";
div.style.height = "200px";
document.getElementById("calcHolder").appendChild(div);
var img = document.createElement("img");
img.setAttribute("src", "{{url_for('static', filename=dxfName+'.png')}}");
img.setAttribute("alt", "no image");
img.setAttribute("height", "120px");
img.setAttribute("width", "120px");
document.getElementById(id_div).appendChild(img);
var array = ["Carbon Steel","Stainless Steel","Aluminium"];
var selectMaterial = document.createElement("select");
document.getElementById(id_div).appendChild(selectMaterial);
for (var i = 0; i < array.length; i++) {
var option = document.createElement("option");
option.value = array[i];
option.text = array[i];
selectMaterial.appendChild(option);
}
var selectThickness = document.createElement("select");
document.getElementById(id_div).appendChild(selectThickness);
for (i = 1; i <= 16; i++) {
var opt = document.createElement('option');
//opt.value = i;
opt.innerHTML = i + ' mm';
selectThickness.appendChild(opt);
}
var quantity = document.createElement("input")
quantity.type="number";
quantity.value="1";
quantity.name="quantity";
quantity.min="1";
quantity.max="50";
quantity.onkeyup= function maxReach(){if(quantity.value > 50) quantity.value=50;};
document.getElementById(id_div).appendChild(quantity);
var btn = document.createElement("button");
btn.innerHTML = "Delete";
btn.type = "button";
document.getElementById(id_div).appendChild(btn);
btn.onclick = function() {div.remove();};
}
</script>
{{ html | safe }}
</div>
</form>
...
Python
#app.route('/upload_files', methods=['POST'])
def upload_files():
try:
if request.method == 'POST':
dxf_file = request.files['dxfUpload']
full_filename = os.path.join(app.config['UPLOAD_FOLDER'],dxf_file.filename)
dxf_file.save(full_filename)
first = DXF2IMG()
first.convert_dxf2img([full_filename],img_format='.png')
html="<img src="+url_for('static', filename=dxf_file.filename+'.png' )+" width='120' height='120' />"
return render_template('upload_files.html',dxfName=dxf_file.filename, html=html)
except:
...
#something happens
The result now
Desired result
Once the form.submit() function is executed, the form will be sent as a regular post request. For this reason, the following function is no longer executed and the entire page is reloaded.
In order to submit the form and change the content of the existing page, it is necessary to use AJAX.
This example shows you how to submit the form to the server and receive a JSON response containing the URLs of the received file and the generated image.
As soon as the submit button is pressed, the form data is packed into a FormData object and sent via AJAX using the fetch function. The browser's default behavior for a submit event is suppressed and the form is reset. The received file is processed by the server and the associated URLs are sent back to the client in JSON format. Now the document can be changed with the received data.
Remember this is just a minimal example to help you achieve your goals and implement your concept.
Flask (app.py)
import os
import ezdxf
from ezdxf.addons.drawing import matplotlib
from flask import Flask
from flask import (
jsonify,
make_response,
render_template,
url_for
)
from werkzeug.utils import secure_filename
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
def dxf2png(source, target):
doc = ezdxf.readfile(source)
msp = doc.modelspace()
auditor = doc.audit()
if auditor.has_errors:
raise Exception('Conversion failed.')
matplotlib.qsave(doc.modelspace(), target)
#app.route('/upload', methods=['POST'])
def upload():
if 'dxf-file' in request.files:
file = request.files['dxf-file']
if file.filename != '':
filename = secure_filename(file.filename)
filepath = os.path.join(app.static_folder, filename)
destname, _ = os.path.splitext(filename)
destname = f'{destname}.png'
destpath = os.path.join(app.static_folder, destname)
file.save(filepath)
try:
dxf2png(filepath, destpath)
except:
os.remove(filepath)
return make_response('', 400)
return make_response(
jsonify(
target=url_for('static', filename=filename),
preview=url_for('static', filename=destname)
),
200
)
return make_response('', 400)
HTML (templates/index.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Index</title>
<style media="screen">
.preview {
width: 120px;
height: auto;
}
</style>
</head>
<body>
<form name="dxf-upload" method="post" enctype="multipart/form-data">
<input type="file" name="dxf-file" />
<input type="submit" />
</form>
<div id="dxf-files"></div>
<script type="text/javascript">
((uri) => {
function createPreview(target, preview) {
const divElem = document.createElement('div');
divElem.innerHTML = `<img src="${preview}" class="preview" />`;
const outElem = document.getElementById('dxf-files');
outElem.append(divElem);
}
const form = document.querySelector('form[name="dxf-upload"]');
form.addEventListener('submit', evt => {
evt.preventDefault();
const formData = new FormData(evt.target);
fetch(uri, {
method: 'POST',
body: formData
}).then(resp => resp.json())
.then(data => {
const { target, preview } = data;
createPreview(target, preview);
});
evt.target.reset();
});
})({{ url_for('.upload') | tojson }});
</script>
</body>
</html>
In my flask app I'm prompting a user to enter numbers manually in the terminal. Those numbers are then sent to the browser to update the DOM. But the problem is that the DOM is updated after function getInputs is completed even though I emit an event after each user's input. So my expectation was the DOM gets updated immediately after the event was emitted (inside the getInput function). What I want is: user enters the first number -> append it to the DOM, user enters the second number -> append it to the DOM. How to do this? Should I refactor my code somehow?
This is my flask app:
from flask import Flask, render_template
from flask_socketio import SocketIO
app = Flask(__name__)
app.config['SECRET_KEY'] = '#secret!'
socketio = SocketIO(app)
#app.route("/")
def home():
return render_template("index.html")
def messageReceived(methods=['GET', 'POST']):
print('message was received!!!')
#socketio.on('my event')
def handle_my_custom_event(json, methods=['GET', 'POST']):
print('received my event: ' + str(json))
socketio.emit('my response', json, callback=messageReceived)
#socketio.on('get inputs')
def get_inputs():
getInput(prompt="First number: ")
getInput(prompt="Second number: ")
def getInput(prompt = "Enter number: "):
x = input(prompt)
socketio.emit('my response', {"number": x})
return x
if __name__ == '__main__':
socketio.run(app, debug=True)
index.html:
<html>
<body>
<button id="btnGetInputs">Get inputs</button>
<ul id="log">
<!-- append elements here -->
</ul>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.7.3/socket.io.min.js"></script>
<script type="text/javascript">
var socket = io.connect('http://' + document.domain + ':' + location.port);
var numbers = []
socket.on('connect', function () {
socket.emit('my event', {
data: 'User Connected'
})
$("#btnGetInputs").click(function () {
socket.emit("get inputs")
})
})
socket.on('my response', function (msg) {
console.log(msg)
if (msg.number) {
numbers.push(msg.number)
items = ''
for (var i = 0; i < numbers.length; i++) {
items = items + '<li>' + numbers[i].toString() + '</li>'
}
$('#log').html(items);
}
})
</script>
</body>
</html>
I have processed the data retrieved from some API in a flask route, extracted the json needed and then stored it in a dictionary. Now, how do I make the processed data appear in a new HTML? Is it a good way to preprocess the data in a flask function, what if the preprocess takes a lot of steps?
Flask python code x.py:
#app.route('/test', methods = ['GET'])
def get_from_api():
url = "https://xxxx"
API_KEY = "xxxx"
params = {
'token' : API_KEY
}
response = requests.get(url, params).json()
city = response['city']
state = response['region']
postal = response['postal']
conutry = response['country']
location = response['loc']
data = {
"city" : city,
"state" : state,
"postal" : postal,
"country" : conutry,
"location" : location
}
Next is the x.html for displaying the data
<div class = "element_val">
<li><div id = "city">null</div></li>
<li><div id = "state">null</div></li>
...
<li><div id = "location">null</div></li>
</div>
How to retrieve the data in flask and put the data in html, and make the html be rendered in '/test'?
#app.route('/test')
def test_route():
user_details = {
'name': 'John',
'email': 'john#doe.com'
}
return render_template('test.html', user=user_details)
<!DOCTYPE html>
<html>
<head>
<title>test</title>
</head>
<body>
<!-- use {{}} to access the render_template vars-->
<p>{{user.name}}</p>
<p>{{user.email}}</p>
</body>
</html>
I have an API made on Flask that has several endpoints. I am trying to use data from these end points to display a chart on my front end that shows the data to the user.
The following are my exact requirements:
Implement one or more types of charts that can be used to effectively visualize data supplied from the API endpoints. Users should be able to pick different metrics to visualize and compare with others.
My Flask API:
import os
from flask import Flask, jsonify, session, request
import sqlalchemy
import time
from functools import wraps
# web app
app = Flask(__name__)
app.secret_key = 'super_secure_key_that_should_be_in_.env'
# database engine
engine = sqlalchemy.create_engine(os.getenv('SQL_URI'))
def rate_limit(**limit_kwargs):
def decorator(function):
#wraps(function)
def wrapper(*args, **kwargs):
limit = limit_kwargs['limit'] if 'limit' in limit_kwargs else 5
seconds = limit_kwargs['window'] if 'window' in limit_kwargs else 60
session_key = 'rate_limit_' + str(request.url_rule)
if session_key not in session:
session[session_key] = []
window: list = session[session_key]
if len(window) < limit:
window.append(int(time.time()))
session[session_key] = window
return function(*args, **kwargs)
if time.time() - window[0] < seconds:
return jsonify(error='Rate limit exceeded'), 429
window.pop(0)
window.append(int(time.time()))
session[session_key] = window
return function(*args, **kwargs)
return wrapper
return decorator
#app.route('/')
#rate_limit()
def index():
return 'Welcome 😎'
#app.route('/events/hourly')
#rate_limit(limit=3, window=20)
def events_hourly():
return queryHelper('''
SELECT date, hour, events
FROM public.hourly_events
ORDER BY date, hour
LIMIT 168;
''')
#app.route('/events/daily')
#rate_limit(limit=2)
def events_daily():
return queryHelper('''
SELECT date, SUM(events) AS events
FROM public.hourly_events
GROUP BY date
ORDER BY date
LIMIT 7;
''')
#app.route('/stats/hourly')
#rate_limit(limit=3, window=20)
def stats_hourly():
return queryHelper('''
SELECT date, hour, impressions, clicks, revenue
FROM public.hourly_stats
ORDER BY date, hour
LIMIT 168;
''')
#app.route('/stats/daily')
#rate_limit(limit=2)
def stats_daily():
return queryHelper('''
SELECT date,
SUM(impressions) AS impressions,
SUM(clicks) AS clicks,
SUM(revenue) AS revenue
FROM public.hourly_stats
GROUP BY date
ORDER BY date
LIMIT 7;
''')
#app.route('/poi')
#rate_limit(limit=3)
def poi():
return queryHelper('''
SELECT *
FROM public.poi;
''')
def queryHelper(query):
with engine.connect() as conn:
result = conn.execute(query).fetchall()
return jsonify([dict(row.items()) for row in result])
My React App.js:
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import DailyEvents from "./Components/DailyEvents";
class App extends Component {
render() {
return (
<div className="App">
<header className= "App-header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-title"> Welcome to React</h1>
</header>
<DailyEvents />
</div>
);
}
}
export default App;
My Components/DailyEvents.js:
import React, { Component } from 'react';
import axios from 'axios';
class App extends Component {
state = {
dates: []
}
componentDidMount() {
axios.get('api_url_or_localhost/events/daily')
.then(res => res.json())
.then((data) => {
this.setState({ dates: data })
})
.catch(console.log)
}
}
export default App;
I keep getting a TypeError that instance.render is not a function.
What I am trying to do is use my Flask API endpoints to visualize the data on the front-end.
try using axios :
https://alligator.io/react/axios-react/
it should look like this :
axios.get('put the query address')
.then(response => {
process your response
})
Can / Should you make changes to the Flask API, or is that code part of the requirements? Because I'm pretty sure you won't be able to return those Date objects straight from the DB without serializing them first.
I suggest you use Postman (or just a browser, for get requests) to test the routes locally and basically have a look at the data first.
React can use Axios or fetch to get this data and visualize it.
import React, { Component } from 'react'
class App extends Component {
state = {
dates: []
}
componentDidMount() {
fetch('api_url_or_localhost/events/daily'))
.then(res => res.json())
.then((data) => {
this.setState({ dates: data })
})
.catch(console.log)
}
...
}
see this https://pusher.com/tutorials/consume-restful-api-react for more details