I am writing a small web app to test my understanding of integrating Angular 1 and Flask. When I try to send output from my Python function to the URL Localhost/synthesize_data, I see a Flask error: 'NoneType Object is not Subscriptable." It is trying to run my Python script again, but I only want it to show the output that the function should already have generated.
HTML with Angular:
<!doctype html>
<html>
<head>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.3/angular.min.js"></script>
<script src="http://code.angularjs.org/1.5.3/angular-route.min.js"></script>
<script>
var myApp = angular.module('myApp', [
'ngRoute',
]);
myApp.config(['$routeProvider',
function($routeProvider) {
$routeProvider.
when('/', {
templateUrl: '/static/partials/index.html',
}).
otherwise({
redirectTo: '/'
});
}]);
myApp.controller('formController', ['$scope', '$http', function($scope, $http) {
console.log('HA');
$scope.formData = {};
$scope.processForm=function() {
console.log("righthere")
$http({
method: 'POST',
url : '/synthesize_data',
data : $scope.formData,
headers: {'Content-Type': 'application/json'}
})
.success(function(data){
console.log(data);
})
};
}])
</script>
<!--<link rel="stylesheet" href="/static/css/style.css" />-->
</head>
<body ng-app="myApp" ng-controller="formController">
<h1>Data Synthesizer Startup Page</h1>
<div>
<form ng-submit = "processForm()">
<div id = "name-group" class = "form-group">
<label>Number of Rows to Create </label>
<input type = "text" name = "name" class = "form-control" placeholder = "Enter valid number input" ng-model = "formData.name">
<span class = "help-block"></span>
</div>
<button type = "submit" class = "btn btn-success btn-lg btn-block">
<span class = "glyphicon glyphicon-flash"></span> Submit
</button>
</form>
<!--<div ng-view></div>-->
</body>
</html>
Python code (initialize program with hello()):
from flask import Flask, send_file, request
from data_synthesis import *
app = Flask(__name__)
#app.route("/synthesize_data", methods=['GET', 'POST'])
def datasynthesize():
print ("Calling synthesizer for ", request.json['name'], " rows.")
main(int(request.json['name']))
return "TEST"
#app.route("/")
def hello():
print ("Python up and running.")
return send_file("templates/start.html")
if __name__ == "__main__":
app.run(debug=True)
What I want is to see "TEST" on the screen when I run this program and navigate to Localhost/synthesize_data. Instead, it attempts to run my Python program again without proper input, which throws the error.
To only execute the program when it has submitted form data you need to add a conditional into the view function. The code the way you have it is dependent on having the name value as part of the request.
Request.json is None if the mimetype is not application/json. This is what is throwing the 'NoneType' Object is not Subscriptable error when you're issue a GET request (e.g. when you navigate to localhost/synthesize_data). A better way of accomplishing this, per the Docs, is to use Request.get_json():
#app.route("/synthesize_data", methods=['GET', 'POST'])
def datasynthesize():
data = request.get_json()
if data:
print ("Calling synthesizer for ", data['name'], " rows.")
main(int(data['name']))
return "TEST"
Related
I am trying to make an Intranet of Things (IoT) page. I am using Flask for the python backend. I am trying to update the state of my light in real time. I believe the route to go is the AJAX/XMLHttpRequest on the front end. I am struggling to figure out how to send the JSON to the front end from the back end. Every example online seems to be a POST request instead of Get.
I believe I have the object created correctly as well as open and sending it correctly. I think my error is on the python side and not doing request right. I tried copying this example https://gist.github.com/KentaYamada/2eed4af1f6b2adac5cc7c9063acf8720. All the other stack overflow examples seem to do different methods like return or add an if statement for the return. I am not sure example how to setup to return the 'get' argument in request.args.get[]. The suggested potential duplicates only show one end, are in express js with the $ syntax which I'm not familiar with, or something similar
I am currently getting 500 errors. Below is my code.
HTML:
<html> <head>
<meta name = "Viewport" context = "width=device-width. initial-scale=1.0">
<title>Chang's IoT Controls</title>
<link href="{{url_for('static',filename='Styles/Controls.css')}}" rel="stylesheet" type="text/css"/>
</head>
<body>
<h1>Controls</h1>
<p> Controls to control Chang's IoT Hub</p>
<figure class="item">
<img src="{{light}}" id="light" onclick="Power(this)" />
<figcaption id = light1 class="caption">Light</figcaption>
</figure>
<figure class="item">
<img src="{{url_for('static',filename='Images/OffLight.jpg')}}" id="temp" onclick="Power(this)" />
<figcaption class="Temperature" id="state" <span style="border:2px solid black">Here</span></figcaption>
<button type = "button" id="toggle" onclick ="Power(this)" > Change Lights </button>
</figure>
<figure class="item">
<img src="{{temp}}" id="temp" onclick="Power(this)" />
<figcaption id = temperature class="caption">{{degree}}</figcaption>
</figure>
<script>
document.getElementById("state").innerHTML = "reached";
const xhttp = new XMLHttpRequest();
xhttp.onload = function () {
const xmlDoc = JSON.parse(this.responseText);
const status = xmlDoc.Status;
document.getElementById("state").innerHTML = status;
if(status == "On")
{
document.getElementById("temp").src = "{{url_for('static',filename='Images/OnLight.jpg')}}";
}
if(status == "Off")
{
document.getElementById("temp").src = "{{url_for('static',filename='Images/OffLight.jpg')}}";
}
}
xhttp.open("GET",'/get_json');
xhttp.send();
console.log(xhttp.response);
</script>
<p>
Homepage
</p>
</body>
</html>
Python:
from flask import Flask, redirect, url_for, render_template, request
app = Flask(__name__)
#app.route("/", methods=["POST", "GET"])
def home():
imgname = url_for('static', filename='Images/OnLight.jpg')
thermo = url_for('static', filename='Images/Thermometer.png')
heat = 50
# if request.method == "GET":
# file = request.form(url_for('static',filename='test.json'))
# return file
return render_template("Controls.html", light=imgname, temp=thermo, degree=heat)
#app.route('/get_json')
def get_json():
return jsonify(Status= "On")
if __name__=="__main__":
app.run(host="0.0.0.0", port=80)
JSON:
{
"Light":
[{"Status": "On"}]
}
I tried looking at examples including git repos like https://gist.github.com/KentaYamada/2eed4af1f6b2adac5cc7c9063acf8720 as well as stack overflow pages like Getting data from xhr request using python and how to properly get data from javascript to my python flask backend using XMLHttpRequest? as well as looked at the APIs
You can create different routes for html and for json.
For your Json try something like below
#app.route(“/get_json“, methods = [“GET”])
def get_json_to_frontend():
// logic
return jsonify( your response)
for html you can use your home() function that you’ve already created
Assume your response is :
{ "state" : "Ok" }
This is what you're Javascript should look like:
let xhttp = new XMLHttpRequest();
xhttp.onload = () => {
let t = JSON.parse(xhttp.response);
console.log(t.state);
}
xhttp.open("GET", URL);
xhttp.send();
This should work. It's pretty straight forward.
for my first stack overflow question, I have been working on a socketio flask chat app tutorial found here codeburst chatapp tutorial
While trying to include the logging headers to debug this 504 error I began running into another Attribute error, this time around the socketio.run line of the main.py file- but the error starts at line 564 of the init.py file with the debug, however this 'eio' object appears in more places than that getting rid of the flask debug mode doesn't fix it.
I have also tried reinstalling flask-socketio and python-engineio. Then I deleted my virtual environment and created a fresh one- still the same eio attribute error.
After spending about 7 hours on this, I think the title of the tutorial should be revised;) Any help would be appreciated.
here is my main.py (with the added logging line commented out)
`app = Flask(__name__)
app.config['SECRET_KEY'] = 'vnkdjnfjknfl1232#'
socketio = SocketIO(app)
# socketio = SocketIO(logger=True, engineio_logger=True)
#app.route('/')
def sessions():
return render_template('session.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)
if __name__ == '__main__':
socketio.run(app, host='0.0.0.0', debug=True)`
hopefully that entered properly, and now for the html part (called session.html here)
<!DOCTYPE html>
<html lang="en">
<head>
<title>Flask_Chat_App</title>
<p>bChat not weChat</p>
</head>
<body>
<h3 style='color: rgb(134, 0, 0);font-size: 30px;'>No message yet..</h3>
<div class="message_holder"></div>
<form action="" method="POST">
<input type="text" class="username" placeholder="User Name"/>
<input type="text" class="message" placeholder="Messages"/>
<input type="submit"/>
</form>
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4="
crossorigin="anonymous"></script>
<script src="https://cdn.socket.io/3.1.3/socket.io.min.js" integrity="sha384-cPwlPLvBTa3sKAgddT6krw0cJat7egBga3DJepJyrLl4Q9/5WLra3rrnMcyTyOnh" crossorigin="anonymous"></script>
<script type="text/javascript">
var socket = io.connect('http://' + 192.168.1.138 + ':' + location.port);
socket.on( 'connect', function() {
socket.emit( 'my event', {
data: 'User Connected'
} )
var form = $( 'form' ).on( 'submit', function( e ) {
e.preventDefault()
let user_name = $( 'input.username' ).val()
let user_input = $( 'input.message' ).val()
socket.emit( 'my event', {
user_name : user_name,
message : user_input
} )
$( 'input.message' ).val( '' ).focus()
} )
} )
socket.on( 'my response', function( msg ) {
console.log( msg )
if( typeof msg.user_name !== 'undefined' ) {
$( 'h3' ).remove()
$( 'div.message_holder' ).append( '<div><b style="color: #000">'+msg.user_name+'</b> '+msg.message+'</div>' )
}
})
</script>
</body>
</html>
And here is the freeze of my pip for my virtual environment
(bChat) pi#raspberrypi:~/bChat $ python -m pip freeze
bidict==0.21.4
click==8.0.4
dnspython==2.2.0
eventlet==0.33.0
Flask==2.0.3
Flask-SocketIO==5.1.1
greenlet==1.1.2
itsdangerous==2.1.0
Jinja2==3.0.3
MarkupSafe==2.1.0
python-engineio==4.3.1
python-socketio==5.5.2
RPi.GPIO==0.7.1
six==1.16.0
Werkzeug==2.0.3
(bChat) pi#raspberrypi:~/bChat $
thanks again for your time. The ultimate goal is to make a near realtime checkbox updater where each checkbox turns a neon light on (checked) and off (unchecked). A friend recommended the socketio chat app. Baby steps.
I'm trying to pass user input into flask python file using JSON..
this is the citizins input element in the html body:
<form class="networkform" method="POST">
<input name="citizens" maxlength="15" class="InputStyle" required>
<button type="submit" style="height: 40px; width: 180px; background-color: grey; color:white">send</button>
</form>
this is the jQuery function in the html file:
$(".networkform").on('submit', function(e){
alert("submit is working")
$.ajax({
data :
{
'citizens' : $("citizens").val(),
},
type : 'POST',
url : '/Dash'
})
.done(function(data){
$(".outerDiv").hide()
})
e.preventDefault();
});
and this is the function in the .py file:
#app.route('/Dash', methods=['POST'])
def Dash():
if request.method == 'POST':
print("inside post")
num_citizins = request.form['citizens']
print(num_citizins)
return jsonify({"msg" : "Thanks"})
and here is the main in .py file:
if __name__ == "__main__":
print 'Start'
main()
app.run(debug=True)
print 'Done!'
But for some reason it's not working at all.. here is the error I get:
BadRequestKeyError: 400 Bad Request: The browser (or proxy) sent a request that this server could not understand.
KeyError: 'citizens'
solutions I already tried:
used app.run(debug=True, threaded=True) instead of app.run(debug=True) in main
used request.form.get instead of request.form
removed method="post" from
but nothing works.. each time it gives a different type of errors.. what do you think the problem could be? (if any of those matter; I'm using python 2.7, IDE: pyCharm, Browser: Chrome)
In Dash() function, change the following line
num_citizins = request.form['citizens']
to
num_citizins = request.json['citizens']
You are sending JSON data which is received in request.json. You also need to set the request content type to application/json for the .json property to work.
Edit
Here's how content type will be set in jQuery. You just need to add contentType : 'application/json' like this:
$.ajax({
data :
{
'citizens' : $("citizens").val(),
},
type : 'POST',
contentType : 'application/json',
url : '/Dash'
})
I have a simple Flask app like so:
import msgpack
from flask import Flask, render_template
app = Flask(__name__)
#app.route('/')
def index():
return render_template('index.html')
#app.route('/test')
def test():
return msgpack.packb([1, 2, 3])
#app.route('/ping')
def ping():
return "Pong"
if __name__ == '__main__':
app.run(debug=True, port=5000)
In the Flask route /test, I'm using msgpack to pack an array which is returned as a response. When this response is printed to the console, it looks something like this: b'\x93\x01\x02\x03'
I'm using AngularJS 1.7 in my front end which looks like:
<!doctype html>
<html ng-app="MyApp">
<body ng-cloak>
<div class="container" ng-controller="MyController">
<h1>Hello, {{text}}</h1>
<button class="btn btn-primary" ng-click="ping()">Ping</button>
<button class="btn btn-primary" ng-click="getMsgpackData()">Get Msgpack Data</button>
</div>
<script src="jquery-3.3.1.slim.min.js"></script>
<script src="/angular.js/1.7.2/angular.min.js"></script>
<script src="https://rawgithub.com/kawanet/msgpack-lite/master/dist/msgpack.min.js"></script>
<script>
var myApp = angular.module("MyApp", []);
myApp.controller("MyController", ["$scope", "$http", function($scope, $http) {
$scope.text = "World";
$scope.ping = function() {
$http.get("/ping").then(function success(response) {
$scope.text = response.data;
}, function error(response) {
console.log(response);
});
}
$scope.getMsgpackData = function() {
$http.get("/test").then(function success(response) {
console.log(response);
$scope.text = msgpack.decode(response.data);
}, function error(response) {
console.log(response);
});
}
}]);
</script>
</body>
</html>
When the getMsgpackData function is invoked in MyController, I get the following error in the browser's console:
Error: Invalid type: 0x�
at n.r [as decode] (msgpack.min.js:1)
at n.fetch (msgpack.min.js:1)
at n.s [as read] (msgpack.min.js:1)
at Object.n [as decode] (msgpack.min.js:1)
at success ((index):46)
at angular.js:17396
at m.$digest (angular.js:18557)
at m.$apply (angular.js:18945)
at k (angular.js:12799)
at V (angular.js:13056) "Possibly unhandled rejection: {}"
It seems like the first HEX value \x93 is not being decoded.
I'm using kawanet/msgpack-lite in the front end as I found that it can be used in a browser.
Please help!
The error message tells you you sent the wrong type of object to the decode() method. The buffer decoding documentation shows that only buffers, arrays and Uint8Array objects are supported.
Change the response type to arraybuffer (from the default text), then feed the response data to msgpack.decode() as a Uint8Array typed array:
$http.get("/test", {responseType: "arraybuffer"}).then(function success(response) {
var arr = new Uint8Array(response.data);
console.log(arr);
$scope.text = msgpack.decode(arr);
}, function error(response) {
console.log(response);
});
While not necessary here, you do want to set a different content type on your Flask response. Currently the /test route is advertising the content as text/html, while you really should be labelling as application/msgpack:
#app.route('/test')
def test():
return msgpack.packb([1, 2, 3]), {'content-type': 'application/msgpack'}
I am trying to get the output from a python script and put it into a table in the html of my cherrypy app.
Example app:
import string, os
import cherrypy
file_path = os.getcwd()
html = """<head>
<meta content="text/html; charset=ISO-8859-1"
http-equiv="content-type">
<title>CCMF</title>
<link rel='shortcut icon' type='image/x-icon' href='img/favicon.ico' />
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>
function b1() {
var request = $.ajax({
url: "b1.py",
type: "POST",
dataType: "text"
});
request.done(function(msg) {
$("#output").html(msg);
});
request.fail(function(jqXHR, textStatus) {
alert( "Request failed: " + textStatus );
});
}
</script>
</head>
<button onclick="b1()">call b1.py</button>
...
<td id = "output"; style="vertical-align: top; height: 90%; width: 100%;">
<--output goes here -->
</td>
...
</html>
"""
class ccmf(object):
#cherrypy.expose
def index(self):
return html
if __name__ == '__main__':
cherrypy.server.socket_host = "127.0.0.1"
cherrypy.server.socket_port = 8084
config = {
"/img": {
"tools.staticdir.on": True,
"tools.staticdir.dir": os.path.join(file_path, "img"),
}
}
cherrypy.tree.mount(ccmf(), "/", config=config)
cherrypy.engine.start()
cherrypy.engine.block()
and here's the example python script b1.py:
def b1():
op = "ajax b1 pushed"
print op
return op
b1()
The ajax get's called but returns the failure alert. I have tried GET, POST, "text", "html", b1.py is in the same directory, no joy. All currently running on my local box.
Any hints greatly appreciated!
You are completely misunderstanding how modern, CherryPy's for instance, routing works. Unlike outdated approaches that were commonly employed with CGI and Apache's mod_* (mod_php, mod_python, etc.), where you directly point to the file containing the script with URL, modern routing is an application level activity.
Your application receives all requests and dispatches them according to the established method. CherryPy in that sense has two major approaches: built-in object tree dispatcher and Routes adapter. For most simple and mid-level cases built-in dispatcher is fair enough.
Basically it can look like this.
app.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import cherrypy
from cherrypy.lib.static import serve_file
path = os.path.abspath(os.path.dirname(__file__))
config = {
'global' : {
'server.socket_host' : '127.0.0.1',
'server.socket_port' : 8080,
'server.thread_pool' : 8
}
}
class App:
#cherrypy.expose
def index(self):
return serve_file(os.path.join(path, 'index.html'))
#cherrypy.expose
#cherrypy.tools.json_out()
def getData(self):
return {
'foo' : 'bar',
'baz' : 'another one'
}
if __name__ == '__main__':
cherrypy.quickstart(App(), '/', config)
index.html
<!DOCTYPE html>
<html>
<head>
<meta http-equiv='content-type' content='text/html; charset=utf-8'>
<title>CCMF</title>
<script type='text/javascript' src='http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js'></script>
<script type='text/javascript'>
$(document).ready(function()
{
$('button').on('click', function()
{
var request = $.ajax({'url': '/getData'});
request.done(function(response)
{
$('#foo').text(response.foo);
$('#baz').text(response.baz);
});
request.fail(function(jqXHR, textStatus)
{
alert('Request failed: ' + textStatus);
});
})
});
</script>
</head>
<body>
<button>make ajax call</button>
<h1>Foo</h1>
<div id='foo'></div>
<h1>Baz</h1>
<div id='baz'></div>
</body>
</html>