Google App Engine: HTTP Error 400: Bad Request - python

I'm working on an application which requires calculating the distance between two locations that were given as input by the user. I'm using Google Map's Distance Matrix API for this purpose. Here's the code:
class MainPage(Handler):
def get(self):
self.render('map.html')
def post(self):
addr1 = self.request.get("addr1")
addr2 = self.request.get("addr2")
url = 'http://maps.googleapis.com/maps/api/distancematrix/json?origins=' + addr1 + '&destinations=' + addr2 + '&mode=driving&sensor=false'
link = urllib2.urlopen(url).read()
self.response.write(link)
map.html
<html>
<head>
<title>Fare Calculator</title>
</head>
<body>
<form method = "post">
Source<input type = 'text' name = "addr1">
Destination<input type = 'text' name = "addr2">
<br><br>
<input type = "submit" value = "Calculate Fare">
</form>
</body>
</html>
map.html contains a basic HTML form with input for the source and destination addresses. However, when I run this application, I get a HTTP Error 400: Bad Request. What's happening?

Your variables need to be urlencoded for the API request.
...
url = 'http://maps.googleapis.com/maps/api/distancematrix/json?origins=' + urllib.quote_plus(addr1) + '&destinations=' + urllib.quote_plus(addr2) + '&mode=driving&sensor=false'
...
You can read more about .quote_plus here.

Related

Taking Input in HTML and analyzing it in python for math equations

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>

Generate dynamic div containers on submit in Flask app

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>

How to make data retrieved from an API in flask shown in a new 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>

how to connect python backend with flask and html&css

'''
app.py
from flask import Flask, render_template, request
from weather_backend import temperature_condition,clothes,feels_temperature,weather_description
app = Flask(__name__)
app.config["SECRET_KEY"] = "Secret-key"
#app.route("/")
def index():
return render_template("index.html")
#app.route("/dress")
def dress():
cityname = request.form.get("city_name")
temp = str(temperature_condition())
message = str(clothes())
feels = feels_temperature
description= weather_description
return render_template("dress.html", message=message, temp=temp, feels_temperature=feels,
weather_description=description )
if __name__ == "__main__":
app.run(debug=True)
'''
'''
weather_backend.py
import requests, json
import weatherMappingMessage
from app import dress
from keys import *
base_url = "http://api.openweathermap.org/data/2.5/weather?"
city_name =
complete_url = base_url + "appid=" + api_key + "&q=" + city_name + "&units=metric"
response = requests.get(complete_url)
'''
HTML file
'''
<body>
<div class="head">
<form action= "{{ url_for('dress') }}" class="form" method="GET">
<h1>Get Weather and Dresses according to the Weather</h1>
<div class = "form-box">
<input type="text" class="search-field location" name= "city_name" placeholder="Location...">
<button class="search-btn" type="button">Search</button>
</div>
</form>
</div>
</body>
'''
I need to get the form info(search) from HTML to the backend(city_name) and then to the flask(cityname)
I can get a message from the backend if try to get it but I can't get HTML form to the backend for processing
The problem I'm facing is that I can't get the form data from my HTML file to my backend for processing
basically, I need the cityname to the backend for getting my weather description
Short answer:
Because your form submission uses a get request, you can use request.args to get parsed contents of query string (see also):
cityname = request.args.get("city_name")
Long answer:
I'm sure you're asking for more than just this piece of code. I took the code you provided and added the missing pieces in-line (please don't do this for production code) and also passed cityname to render_template:
import logging
from datetime import datetime
from flask import render_template, request
from app import app, forms
#app.route("/")
def index():
return render_template("index.html")
#app.route("/dress")
def dress():
cityname = request.args.get("city_name")
# missing in example code
def temperature_condition():
return 'temp cond'
# missing in example code
def clothes():
return 'clothes'
feels_temperature = 'feels temp' # missing in example code
weather_description = 'weather desc' # missing in example code
temp = str(temperature_condition())
message = str(clothes())
feels = feels_temperature
description = weather_description
return render_template("dress.html", message=message, temp=temp, feels_temperature=feels,
weather_description=description, cityname=cityname) # also pass cityname
I created a minimalistic dress.html:
<html>
<body>
<p>message = {{ message }}</p>
<p>temp = {{ temp }}</p>
<p>feels_temperature = {{ feels_temperature }}</p>
<p>weather_description = {{ weather_description }}</p>
<p>cityname = {{ cityname }}</p>
</body>
</html>
Starting the application via flask run allows me to input a city name into the form field and view the results (for example 'Berlin'):
In order to show the weather description for the chosen city, you could create a function that accepts the city name and retrieves the information from the web (just a rough sketch):
import requests, json
import weatherMappingMessage
from app import dress
from keys import *
def weather_for_city(city_name):
base_url = "http://api.openweathermap.org/data/2.5/weather?"
complete_url = base_url + "appid=" + api_key + "&q=" + city_name + "&units=metric"
response = requests.get(complete_url)
if response.status_code == 200:
return response.json() # assumes your API returns a JSON response
else:
# perform some error handling here, maybe apply a retry strategy
pass
Extract the relevant data from the result of weather_for_city and pass it to render_template like you did for the other variables.

How to use a same variable in two different functions in flask without declaring in global space [duplicate]

This question already has answers here:
Are global variables thread-safe in Flask? How do I share data between requests?
(4 answers)
Store large data or a service connection per Flask session
(1 answer)
Closed 2 years ago.
I am taking input(city name) from the user using a form and using the input(city name) I am fetching a real time weather data after some pre processing a 'sample' numpy variable is created and I am trying to use 'sample' in a different funtion to display the output on a different page.
Here is the app.py code:
from flask import Flask, request, jsonify, render_template
import requests
import math
import numpy as np
import pickle
app = Flask(__name__)
modelMLR = pickle.load(open('modelMLR.pkl','rb'))
#app.route('/')
def home():
return render_template('main.html')
#app.route('/algos', methods = ['GET','POST'])
def algos():
city = request.form['location']
api_address = "https://api.openweathermap.org/data/2.5/weather?appid=33a306ae5533eae0fe34e94953cde0a7&q="
url = api_address+city
json_data = requests.get(url).json()
#for Multiple linear Regression
L1=[]
#temperature
kelvin_temp = json_data["main"]["temp_min"]
celcisus_temp = kelvin_temp - 273.15
fahrenheit_temp = celcisus_temp * ( 9 / 5 ) + 32
formatted_data1 = math.floor(fahrenheit_temp)
L1.append(formatted_data1)
kelvin_temp = json_data["main"]["temp_max"]
celcisus_temp = kelvin_temp - 273.15
fahrenheit_temp = celcisus_temp * ( 9 / 5 ) + 32
formatted_data2 = math.floor(fahrenheit_temp)
L1.append(formatted_data2)
#Humidity
L1.append(80)
formatted_data4 = json_data["main"]["humidity"]
L1.append(formatted_data4)
#sea level pressure
L1.append(990)
L1.append(1010)
formatted_data5 = json_data["main"]["pressure"]
L1.append(formatted_data5)
#cloud cover
formatted_data6 = json_data["clouds"]["all"]
L1.append(formatted_data6)
L1.append(formatted_data6)
L1.append(formatted_data6)
L1.append(formatted_data6)
#shortwave radiation
L1.append(0)
#wind speed
L1.append(0)
formatted_data7 = json_data["wind"]["speed"]
L1.append(formatted_data7)
#wind gust
L1.append(0)
L1.append(0)
sample = np.array(L1)
sample= sample.reshape(1, -1)
return render_template("algos.html")
#app.route('/MLR')
def predict_MLR():
prediction = modelMLR.predict(sample)
return render_template('MLR.html', prediction_text = "The current precipitation is: {}".format(prediction))
if __name__ == "__main__":
app.run(debug = False)
I want to use variable 'sample' of algos() function in predict_MLR() function so that I can predict the output and display it on MLR.html page.
main.html:
<!doctype html>
<body>
<h1> Rainfall prediction.. </h1><br>
<form method = "POST" action="{{url_for('algos')}}">
<button type="button"><img width="13px" height="13px" src="back.jpg"></button>
<input type = "text" placeholder="Search for your city.." style="width:300px" name = "location">
<button type = "submit" value="submit"><img src = "search.png" height="13px" width="13px"></button>
</form>
</body>
</html>
algos.html:
<!doctype html>
<html>
<body>
<h1> Rainfall prediction.. </h1><br>
<h1>Multiple Linear Regression<h1>
</body>
</html>
MLR.html:
<!doctype html>
<html>
<h1> Rainfall prediction.. </h1><br>
<h2>{{prediction_text}}</h2>
</html>
A simpler way to write this would be to first define the agios function which returns sample:
def algos(city):
api_address = "https://api.openweathermap.org/data/2.5/weather?appid=33a306ae5533eae0fe34e94953cde0a7&q="
url = api_address+city
json_data = requests.get(url).json()
#for Multiple linear Regression
L1=[]
#temperature
kelvin_temp = json_data["main"]["temp_min"]
celcisus_temp = kelvin_temp - 273.15
fahrenheit_temp = celcisus_temp * ( 9 / 5 ) + 32
formatted_data1 = math.floor(fahrenheit_temp)
L1.append(formatted_data1)
kelvin_temp = json_data["main"]["temp_max"]
celcisus_temp = kelvin_temp - 273.15
fahrenheit_temp = celcisus_temp * ( 9 / 5 ) + 32
formatted_data2 = math.floor(fahrenheit_temp)
L1.append(formatted_data2)
#Humidity
L1.append(80)
formatted_data4 = json_data["main"]["humidity"]
L1.append(formatted_data4)
#sea level pressure
L1.append(990)
L1.append(1010)
formatted_data5 = json_data["main"]["pressure"]
L1.append(formatted_data5)
#cloud cover
formatted_data6 = json_data["clouds"]["all"]
L1.append(formatted_data6)
L1.append(formatted_data6)
L1.append(formatted_data6)
L1.append(formatted_data6)
#shortwave radiation
L1.append(0)
#wind speed
L1.append(0)
formatted_data7 = json_data["wind"]["speed"]
L1.append(formatted_data7)
#wind gust
L1.append(0)
L1.append(0)
sample = np.array(L1)
sample= sample.reshape(1, -1)
return sample
Then have a single route which returns a different result based on the request.method:
#app.route('/')
def home():
if request.method == 'POST':
city = request.form['location']
sample = algos(city)
prediction = modelMLR.predict(sample)
return render_template('main.html', prediction_text = "The current precipitation is: {}".format(prediction))
else:
# GET request, just render the home page
return render_tempate('main.html')
if __name__ == "__main__":
app.run(debug = False)
Notice that prediction_text is only passed through in the event of a POST request.
Now just define a template which handles this case with an if clause:
<!doctype html>
<body>
<h1> Rainfall prediction.. </h1><br>
<form method = "POST" action="{{url_for('home')}}">
<button type="button"><img width="13px" height="13px" src="back.jpg"></button>
<input type = "text" placeholder="Search for your city.." style="width:300px" name = "location">
<input type = "submit" value="submit" />
</form>
{% if prediction_text %}
<h1> Rainfall prediction.. </h1><br>
<h2>{{prediction_text}}</h2>
{% endif %}
</body>
</html>
In the event that you hit the / endpoint with a GET request, the prediction is not shown.

Categories

Resources