Flask render html only when post api gets data - python

I'm trying to build an app that when the api comes with different colors the html will be rendered automaticaly. I have this but does nothing :(
app.py
from flask import Flask, render_template, jsonify, request
import time
import os, sys
import json
app = Flask(__name__)
#app.route("/")
def home():
return render_template('index.html')
#app.route("/api/green", methods=['POST'])
def green():
data = request.get_json()
templateData = {
'fname' : data["green"]
}
return render_template('green.html', **templateData)
#app.route("/api/red", methods=['POST'])
def red():
data = request.get_json()
templateData = {
'fname' : data["red"]
}
return render_template('red.html', **templateData)
#app.route("/api/orange", methods=['POST'])
def orange():
data = request.get_json()
templateData = {
'fname' : data["orange"]
}
return render_template('orange.html', **templateData)
if __name__ == "__main__":
app.run(host='0.0.0.0', port=5000, debug=True)
index.html
<!DOCTYPE html>
<head>
<title>Title</title>
<link rel="stylesheet" href="../static/style.css/">
<!-- <meta http-equiv="refresh" content="5" /> -->
</head>
<body>
<div class="content container">
{% block main %}{% endblock main %}
</div>
</body>
</html>
the other html files
//green.html
{% extends 'index.html' %}
{% block main %}
<h2>{{ green }}</h2>
{% endblock main %}
//red.html
{% extends 'index.html' %}
{% block main %}
<h2>{{ red }}</h2>
{% endblock main %}
//orange.html
{% extends 'index.html' %}
{% block main %}
<h2>{{ orange }}</h2>
{% endblock main %}
The best would be to create whole new template html files for all the cases and then after a certain time to redirect to index.

In the templates red.html, orange.html & green.html, the variable name used are red, orange & green respectively. But you are sending no such variable to these HTML files.
Try something like this:
#app.route("/api/green", methods=['POST'])
def green():
data = request.get_json()
templateData = {
'fname' : data["green"]
}
return render_template('green.html', green=templateData) #Change in this line
Do this for all other routes also.

Related

flask-mongoengine model_form is missing a submit field - how do I append one to the form?

I am using generic MethodViews in my Flask application together with Flask-MongoEngine. I am also trying to automate form creation based on the given model by using the model_form(db_model) function. Lastly, I am trying to let Bootstrap-Flask take care of rendering the produced form. The problem is that there is no submit button, because the form returned by model_form does not include a SubmitField.
Is there a way to append a submit field before the form is rendered?
Here is a minimally viable app
from datetime import datetime
from flask import Flask, Blueprint, render_template, url_for
from flask_mongoengine import MongoEngine
from flask_bootstrap import Bootstrap5
db = MongoEngine()
bootstrap = Bootstrap5()
class Role(db.Document):
meta = { 'collection': 'roles' }
name = db.StringField(verbose_name='Role Name', max_length=24, required=True, unique=True)
description = db.StringField(verbose_name='Role Description', max_length=64, default=None)
date_created = db.DateTimeField(default=datetime.utcnow())
date_modified = db.DateTimeField(default=datetime.utcnow())
def get_id(self):
return str(self.id)
def safe_delete(self):
if self.name == 'admin':
return False, 'Admin role is not removable.'
result, resp = self.delete()
if not result:
return result, resp
return True, f'Privilege {self.name} removed successfully'
class AuthItemView(MethodView):
def __init__(self, model, template):
self.model = model
self.template = template
def _get_item(self, id):
return self.model.objects.get_or_404(id=id)
def get(self, id):
item = self._get_item(id)
return render_template(self.template, item=item)
class AuthItemEditor(AuthItemView):
def _get_form(self):
form = model_form(self.model, exclude=['date_created', 'date_modified'])
return form()
def get(self, id):
item = self._get_item(id)
form = self._get_form()
return render_template(self.template, item=item, form=form)
def post(self, id):
return 'Yay! Role changes were posted!', 200
staff_bp = Blueprint('staff', __name__)
staff_bp,add_url_rule('/roles/<id>', view_func=AuthItemView.as_view('role_info', Role, 'roleinfo.html')
staff_bp.add_url_rule('/roles/<id>/edit', view_func=AuthItemEditor.as_view('role_edit', Role, 'roleedit.html')
def create_app():
app = Flask(__name__)
app.config['MONGODB_SETTINGS'] = {
'db': 'someapp',
'host': 'localhost',
'port': 27017
}
app.config['SECRET_KEY'] = 'some-very-secret-key'
app.register_blueprint(staff_bp)
db.init_app(app)
bootstrap.init_app(app)
return app
if __name__ == __main__:
a = create_app()
a.run()
The roleedit template is where the magic has todoesn't happen:
{% extends 'base.html' %}
{% from 'bootstrap5/form.html' import render_form %}
{% block content %}
<h1>Edit Properties of <em>{{ item.name }}</em></h1>
<p>
{{ render_form(form) }}
<!-- There is no submit button!!! How do I submit??? //-->
</p>
{% endblock %}
Here is a very basic base template:
<!doctype html>
<html lang="en">
<head>
{% block head %}
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
{% block styles %}
<!-- Bootstrap CSS -->
{{ bootstrap.load_css() }}
{% endblock %}
<title>Page title</title>
{% endblock %}
</head>
<body>
<!-- Your page content -->
{% block content %}{% endblock %}
{% block scripts %}
<!-- Optional JavaScript -->
{{ bootstrap.load_js() }}
{% endblock %}
</body>
</html>
Lastly, the roleinfo template (it's there just to be able to run the app):
{% extends 'base.html' %}
{% block content %}
<h1>Properties of <em>{{ item.name }}</em></h1>
<!-- display item properties as a table or as responsive bootstrap grid //-->
{% endblock %}
You can pass a Form class to model_form. For example:
class BaseForm(Form):
submit = SubmitField('Submit')
class AuthItemEditor(AuthItemView):
def _get_form(self):
form = model_form(self.model, base_class=BaseForm, exclude=['date_created', 'date_modified'])
return form()
# ...
Turns out, it is rather easy...
# ... other imports ...
from wtforms import SubmitField
# ... inside the get_form function
form = model_form(self.model)
setattr(form, 'submit', SubmitField('Submit'))
# now return the fixed form
If anyone has a different approach, please share!

Having problems with the usage of a block in Flask

so I tried bulding a (small) website (for learning purposes) and had a few problems with the usage of a block.
I have the feeling that the problem is something obvious, but I can't figure it out.
Here is my code:
# main.py
from flask import Flask, render_template
app = Flask(__name__)
#app.route("/")
def home():
return render_template("main.html")
if __name__ == "__main__":
app.run(debug=True)
# main.html
<!DOCTYPE html>
<head>
<title>
{% block title %}{% endblock %}
</title>
</head>
<body>
{% block content %}{% endblock %}
</body>
</html>
# mainexdended.html
{% extends "main.html" %}
{% block title %}Test{% endblock %}
{% block content %}
<h1> Content Test </h1>
{% endblock %}
Now, when I run the code, I just get a blank page. Everything defined in the mainextended.html gets ignored.
How can I change that?
That's because you are rendering main.html, not mainextended.html.
You need to change
#app.route("/")
def home():
return render_template("mainextended.html")
Than you should see the contents of both, main.html and mainextended.html
If you use "extend" you always want to render the "extending" html, there is also a function to include content tho, which would work the other way round.

Using Google Charts with Flask dynamically

I am completely new to App building with Flask and Python.
I am trying to create Google column charts, which change dynamically, when i change the data in my Phython file.
I tried a lot of different way, which are described on stackoverflow, but they dont fit to my demand.
I have no knowledge about Javascript.
My data look like this list:
Status = [('active', '106297'), ('inactive', '236'), ('planned', '27453')]
#app.route('/test03')
def test03():
return render_template('chart.html', **globals())
I already tried to convert this list into JSON, but i wasn't able to find the right format.
Would be really nice, if you can help me. :)
Update:
from flask import Flask, render_template, request, jsonify, url_for
import gviz_api
# Creating the data
description = {"name": ("string", "Name"),
"salary": ("number", "Salary")}
data = [{"name": "Mike", "salary": 10000},
{"name": "Jim", "salary": 800},
{"name": "Alice", "salary": 12500},
{"name": "Bob", "salary": 7000}]
# Loading it into gviz_api.DataTable
data_table = gviz_api.DataTable(description)
data_table.LoadData(data)
# Create a JavaScript code string.
jscode = data_table.ToJSCode("jscode_data",
columns_order=("name", "salary"),
order_by="salary")
# Create a JSON string.
jsonData = data_table.ToJSon(columns_order=("name", "salary"),
order_by="salary")
print("Finish")
app = Flask(__name__)
# charts = GoogleCharts(app)
#app.route('/')
def test():
return render_template('chart.html', **globals())
if __name__ == '__main__':
# app.run(debug=True, host='192.168.43.183', port=800) # Home
and the chart.html file:
{% extends 'base.html' %}
{% block head %}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
// Define the chart to be drawn.
var data = new google.visualization.DataTable(jsonData);
// Instantiate and draw the chart.
var chart = new google.visualization.ColumnChart(document.getElementById('myPieChart'));
chart.draw(data, null);
}
</script>
{% endblock %}
{% block body %}
<h1>Hello, this is my Columnchart-Test</h1>
<!-- Identify where the chart should be drawn. -->
<div id="myPieChart"></div>
{% endblock %}
and the base.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="{{ url_for('static', filename='css/main.css') }}" type="text/css" rel="stylesheet">
{% block head %}{% endblock %}
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
But it still doesn't work. - I think there is a problem with the transfer of jsonData to JS.
I recently ran into the same exact problem when I was trying to create a chart for a web app I was making and even considered using chart.js because I suspected it would be easier but I found a solution. What you need to do is pass in the data to be graphed as a dictionary then loop through it using jinja formatting in the html file. i.e.
from flask import Flask, render_template, request, jsonify, url_for
import gviz_api
#app.route('/')
def test():
return render_template('chart.html', data={"Name":"Salary", "Mike":10000, "Jim":800, "Alice":12500,"Bob":7000})
if __name__ == '__main__':
app.run(debug=True)
And the chart.html should be something like this
{% extends 'base.html' %}
{% block head %}
<script src="https://www.gstatic.com/charts/loader.js"></script>
<script>
google.charts.load('current', {packages: ['corechart']});
google.charts.setOnLoadCallback(drawChart);
function drawChart() {
// Define the chart to be drawn.
var data = new google.visualization.arrayToDataTable([
{% for k, v in data.items() %}
{% if v is string %}
['{{ k }}', '{{ v }}'],
{% else %}
['{{ k }}', {{ v }}],
{% endif %}
{% endfor %}
]);
// Instantiate and draw the chart.
var chart = new google.visualization.ColumnChart(document.getElementById('myPieChart'));
chart.draw(data, null);
}
</script>
{% endblock %}
{% block body %}
<h1>Hello, this is my Columnchart-Test</h1>
<!-- Identify where the chart should be drawn. -->
<div id="myPieChart"></div>
{% endblock %}
I dont think any changes need to be made to the base.html file. This worked for me so I think it should work for you too.
You need to add {{ jsonData || safe }} in the template part and you just need to put the jinja bit.
I'm not sure about globals but jsonData=jsonData in the app.py returns template bit.
Template:
var data = new google.visualization.DataTable( {{ jsonData|safe }} );
app.py:
return render_template('chart.html', jscode=jscode, jsonData=jsonData)

Method Not Allowed in Flask for IntegerField form

I'm trying to set up integer field validation on a form in Flask, but I keep getting 'Method Not Allowed'. I can't see what is wrong with my routes?
My main file is:
from flask import Flask, render_template
from flask_wtf import FlaskForm
from wtforms import IntegerField
# from perfect_numbers import classify
app = Flask(__name__)
app.config['SECRET_KEY'] = 'MySecretKey'
# num = 12
# Classify = classify(num)
class PerfectForm(FlaskForm):
number = IntegerField(4)
#app.route('/', methods=['POST'])
def form():
form = PerfectForm()
return render_template('index.html', form = form)
if __name__ == '__main__':
app.run(debug=True)
Then I have a standard layout.html file:
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="utf-8">
<title>PERFECT App</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/js/bootstrap.min.js" integrity="sha384-vBWWzlZJ8ea9aCX4pEW3rVHjgjt7zpkNpZk+02D9phzyeVkE+jo0ieGizqPLForn" crossorigin="anonymous"></script>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
And my index.html is:
{% extends 'layout.html' %}
{% block body %}
<h1>PERFECT NUMBERS</h1>
<p>This is a basic Flask App to illustrate Aliquot Sums and Perfect Numbers</p>
<p>Input a number to check if it is abundant, perfect, or deficient</p>
<form action="{{ url_for('/') }}" method="POST">
{{ form.csrf_token }}
{{ form.number }}
</form>
<!-- {{ num }} is {{ classify }} -->
{% endblock %}
First, change the app.route() signature to
#app.route('/', methods=['POST', 'GET'])
You have to fill the form and submit for your app to receive a POST request. When you first load the page on your browser, you technically send a GET request to flask, and it returns the page.
To handle your POST request separately, do something like this :
#app.route('/', methods=['POST', 'GET'])
def form():
if request.method == 'POST':
# Do something with request (access form elements with request.get(key))
return 'Somehing here'
form = PerfectForm()
return render_template('index.html', form = form)

How to pass multiple templates to flask.render_template()

I'm trying to deploy a flask app and I want a flask.render_template() method passed with a list of html files. Here I see it's eligible. http://flask.pocoo.org/docs/0.12/api/#flask.render_template
I'm trying with this code
from flask import Flask, render_template
app = Flask(__name__)
app.debug = True
#app.route('/')
def hello():
templs = ["_header.html", "_footer.html"]
return render_template(templs)
if __name__== '__main__':
app.run()
But actually server returns only the first template from the list.
How to iterate though this list in order to render all templates from the list?
Thanks,
Alex
As far as i see you are trying to render static header and footer. I'd recommend to prepare something like "layout.html" with included header and footer:
//layout.html
<html>
<head>//headhere</head>
<header>//your static header</header>
<main>
{% block body %}
//content will be here
{% endblock %}
</main>
<footer> //your static footer </footer>
</html>
then in "child" templates(ex: index.html)use:
//index.html
{% extends "layout.html" %}
{% block body %}
//your code here
{% endblock %}
It will render header and footer from layout.html and rest from index.html.
You probably don't want to render multiple templates. What you want is to render one template that combines multiple templates. That is the task of templating engine, not Flask. See http://jinja.pocoo.org/docs/dev/templates/ (Flask uses Jinja).
Exactly like #jbasko wrote!
Making use of two {{block}} statements worked for me:
For example, I put in my routes.py
#app.route("/page1")
def page1():
return render_template('page1.html', title='Title')
the page1.html is containing simply two block-specifications
{% extends "page1.html" %}
{% block content %}
<h1> Content </h1>
{% endblock content %}
{% block info %}
<h1> Info </h1>
{% endblock info %}
which gets referenced in layout.html in two separate places:
{% block content %}{% endblock %}
and later
{% block info %}{% endblock %}
Thanks for the help everyone!
you can try this...
from flask import Flask, render_template
app = Flask(__name__)
app.debug = True
#app.route('/')
def hello():
render_header = render_template('_header.html')
render_footer = render_template('_footer.html')
return render_header + render_footer
if __name__ == '__main__':
app.run()

Categories

Resources