So trying to finish a lab using Flask Templates
Here is my python code:
cryptosnapshots = (requests.get(f"https://api.finage.co.uk/snapshot/crypto?quotes=false&trades=true&symbols=&apikey=XXX")).json()
snapshot = (cryptosnapshots['lastTrades'][:20])
#app.route('/crypto_data', methods = ['GET']) # define the first route, the home route
def show_crypto(): # define the function that responds to the above route
if request.method == 'GET':
return render_template('show.html', snapshot = snapshot)
if __name__ == '__main__':
app.run()
and here is my the code from the html page:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
{% for snapshot in snapshots %}
<h2>Symbol: {{snapshot['s']}}</h2>
<p> Last Price: {{snapshot['p']}}<p>
{% endfor %}
</body>
</html>
When python returns the url and I add my "/crypto_data" endpoint, the page just shows up blank...is my error on the python side or the html side (or is it the api??)?
TIA!
Im expecting the url and endpoint to lead to an html list of all the last trading price from the first 20 cryptos on the list.
My first issue was breaking down the API json and I thought once that was solved it would be a breeze...
labs due Sunday, someone help lol
In the Jinja template, your are accessing a value name snapshots. But in your Flask code, you are defininig a value name snapshot.
Try replacing the value named snapshot by snapshots in your Flask app:
cryptosnapshots = (requests.get(f"https://api.finage.co.uk/snapshot/crypto?quotes=false&trades=true&symbols=&apikey=XXX")).json()
snapshot = (cryptosnapshots['lastTrades'][:20])
#app.route('/crypto_data', methods = ['GET']) # define the first route, the home route
def show_crypto(): # define the function that responds to the above route
if request.method == 'GET':
return render_template('show.html', snapshots = snapshot)
if __name__ == '__main__':
app.run()
Related
I am having some trouble applying the code in the WTForms documentation to my use case (see "Dynamic Form Composition" section). My goal is to use a list of strings (list_a, of variable length) as an argument to produce a series of checkbox forms. For example, if list_a = ['one, 'two'], then the output would be a form with two checkboxes labeled "one" and "two". The documentation says to use this:
def my_view():
class F(MyBaseForm):
pass
F.username = StringField('username')
for name in iterate_some_model_dynamically():
setattr(F, name, StringField(name.title()))
form = F(request.POST, ...)
# do view stuff
and in my attempt to appropriate it, I've come up with this:
def wrapper_func(list_a):
class Prefs(FlaskForm):
pass
for ele in list_a:
setattr(Prefs, ele, BooleanField(ele) )
form = Prefs(request.POST, ...)
Can anyone help me clean this up to get it to work? I'm not sure what else goes in the last line, or if a list is even allowed in this context. Any input would be greatly appreciated!
Based on your question it's hard to decide whether you are using WTForms or Flask-WTF. The documentation link points to the former, while your example uses the FlaskForm class, which is part of the latter.
The following minimalistic example is made using WTForms.
Project structure:
your_project_folder
├───forms
│ ├───__init__.py
│ └───dynamic_form.py
├───templates
│ └───main.html
├───venv
│ └───your_virtual_environment_files
└───server.py
dynamic_form.py contains your wrapper function without the form instantiation (it just returns the dynamically created form class):
from wtforms import Form, BooleanField
def wrapper_func(list_a):
class Prefs(Form):
pass
for ele in list_a:
setattr(Prefs, ele, BooleanField(ele))
return Prefs
main.html contains the HTML code with Jinja2 syntax to generate the form:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<form method="POST">
{% for field in form %}
<div>{{ field.label }}: {{ field }}</div>
{% endfor %}
<button type="submit">Submit</button>
</form>
</body>
</html>
server.py puts everything together:
from flask.app import Flask
from flask import request, render_template, redirect
from forms.dynamic_form import wrapper_func
app = Flask('form_app')
#app.route('/', methods=['GET', 'POST'])
def main():
input_list = ['one', 'two', 'three'] # generate it as needed
prefs = wrapper_func(input_list)
form = prefs(request.form)
if request.method == 'POST' and form.validate():
# do your logic with the submitted form data here
return redirect('/')
return render_template("main.html", form=form)
if __name__ == '__main__':
app.run(host='localhost', port=3456, debug=True)
The last two lines are strictly for development purpose!
Please let me know if this example helps!
Ive made a flask script which runs fine however im trying to display some values in a table on another html page which for some reason is not happening.
i've already tried going through jinja2 documentation and a few other answers but it didn't help much.
the flask file.py
from flask import Flask,render_template,request
app = Flask(__name__)
from webscraper import keeda,display_tbl
#app.route('/', methods=['POST', 'GET'])
def scraper():
if request.method == 'POST':
url = request.form['url']
df=keeda(url)
return render_template(('completed.html',display_tbl(df)))
else:
return render_template('index.html')
if __name__ == '__main__':
app.run()
the completed.html file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Summary of Scraped Data</title>
</head>
<body>
<h1>This is what you got! </h1>
<div>
{{ display_tbl(df) }}
</div>
</body>
</html>
here's the error: jinja2.exceptions.UndefinedError: 'display_tbl' is undefined
i wanted to display a table with values on this page.
You are expecting more than what jinja2 can do for you. Please understand jinja2 is just a way to render templates which are eventually html and javascript, nothing fancy. So, in your case you cannot pass a Python function to your jinja2 template and expect that to run fine. What you can do here is to pass the data returned by display_tbl while rendering template like this:
def scraper():
...
return render_template(('completed.html', data=display_tbl(df))) # data= is important because this is how you are going to access your data in the template
…
def display_tbl(df):
… # Here you should be returning the data you want to display - a list or dict
In the template
<html>
<head>
<meta charset="UTF-8">
<title>Summary of Scraped Data</title>
</head>
<body>
<h1>This is what you got! </h1>
<div>
{{ render_data() }}
</div>
<script>
var d = data | tojson
function render_data() {
// implement the logic to handle how your data should be rendered
}
</script>
</body>
</html>
This is just a rough idea but as you can see you need to change the way you are perceiving jinja2 templates and their interaction with Python or Flask backend.
I'm trying to create a simple search tool that searches an existing Postgres table, using Flask, Jinja & SQLAlchemy.
It's all working, except when I search, the result that is displayed on my page is like this:
Note the bit i've circled, is what would be displayed if I did the same search just using Postgres/pgadmin. It's returning multiple random results.
Below is what would return by using Pgadmin:
Any ideas? My code is below.
App.py
from flask import Flask, render_template, request
from sqlalchemy import create_engine
from sqlalchemy import text
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI']='xxx://xxx:xxx#xxx:xxx/xxx'
engine = create_engine('postgresql+psycopg2://xxx:xxx#xxxr:xxx/xxx')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db=SQLAlchemy(app)
#app.route('/', methods=['GET', 'POST'])
def homepage():
if request.method == 'POST':
jn = request.form['jobnumber']
rp = db.session.execute(text("SELECT cost FROM public.options where cast(optionno AS VARCHAR) like :jn"), {"jn": f"%{jn}%"})
result_set = rp.fetchall()
return render_template('main.html', result_set=result_set, jn=jn)
else:
return render_template('main.html')
if __name__ == "__main__":
app.run(debug=True)
Main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>xxx</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
</head>
<body>
<p>xxx</p>
<form method="POST" id="jobnumber">
<input name="jobnumber" type="text" placeholder="jobnumber">
</form>
<table>
<td>
<h1> Results</h1>
<p>{{result_set}}</p>
</td>
</table>
</body>
</html>
How do I get it to only display the same as what PGAdmin would display?
You seem to be searching with %s in flask & without them in pgAdmin. If you need the same result in both, use the same query.
Enclosing the search string with % indicates to the SQL engine that you want to have values that contain your search string. Not just an exact match.
This question already has an answer here:
Flask view shows 400 error instead of template with form
(1 answer)
Closed 4 years ago.
I'm trying to create a flask app where I have a text box on the webpage. When submit is pressed it searches what was entered into the text box in a postgres datbase table.
I'm getting the following error:
Bad Request The browser (or proxy) sent a request that this server could not
understand."
My code is as follows:
app.py
from flask import Flask, render_template, request
from sqlalchemy import create_engine
app = Flask(__name__)
app.config['DEBUG']
db_string = "postgres://xx:xx#xx:5432/xx"
db = create_engine(db_string)
#app.route('/', methods=['GET', 'POST'])
def homepage():
jn = request.form['jobnumber']
result_set = db.execute("SELECT cost FROM public.options where optionno = (f'%{jn}%')").fetchall()
return render_template('main.html', test=result_set, jn=jn)
if __name__ == "__main__":
app.run(debug=True)
and my html file:
main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>xxx</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="{{ url_for('static', filename='css/bootstrap.min.css') }}" rel="stylesheet">
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
</head>
<body>
<p>xxx</p>
<form method="POST">
<input name="jobnumber" type="submit" placeholder="jn">
</form>
<table>
<td>
{{test}}
</td>
</table>
</body>
</html>
I'm sure it's something real easy and simple that will fix it, but i'm struggling so any help would be hugely appreciated.
Since your homepage function receives both GET and POST requests you need to handle each case separately. You don't have request.form when you recieve GET request.
#app.route('/', methods=['GET', 'POST'])
def homepage():
if request.method == 'POST'
jn = request.form['jobnumber']
result_set = db.execute("SELECT cost FROM public.options where optionno = (f'%{jn}%')").fetchall()
return render_template('main.html', test=result_set, jn=jn)
else:
return render_template('main.html')
Please be aware that it's dangerous to put user's input directly into your SQL query without sanitizing it as it opens your app to SQL injection attacks.
I want to make a simple python script to be run in my server. What it's supposed to do is receive requests and return values according to requests it received.
I want to access the script with a way like http://example.com/thescript.py?first=3&second=4.
and make the script to read the first and second and to do jobs with the values.
How could I do this?
The easiest way is to use Flask:
from flask import Flask, request, render_template
app = Flask(__name__)
#app.route('/', methods=['GET', 'POST'])
def index():
first = request.args.get('first')
second = request.args.get('second')
return render_template('index.html', first=first, second=second)
if __name__ == '__main__':
app.run()
And the template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
First: {{ first }}
<br />
Second: {{ second }}
</body>
</html>
This code will simply print the two parameters provided.