how to render template in flask without using request context - python

So there's this flask app that I'm working on for this project and I need it to run in a loop at timed variables to check for the status of certain variables and then give a output accordingly. However, the problem I have is I need to render a template in Flask before the loop restarts. In the changelog on http://flask.pocoo.org/ it's indicated that it's possible to render templates without using the request context but I haven't seen any real examples of this. So is there a way to render templates in Flask without having to use the request context without getting any errors? Any help that can be given is appreciated.
UPDATE:
Here's the code I'm working with
from flask import Flask, render_template, request, flash, redirect, url_for
import flask
import time
from flask.ext.assets import Environment, Bundle
from flask_wtf import Form
from wtforms import TextField, TextAreaField, SubmitField
from wtforms.validators import InputRequired
CSRF_ENABLED = True
app = Flask(__name__)
app.secret_key = 'development key'
app = flask.Flask('my app')
assets = Environment(app)
assets.url = app.static_url_path
scss = Bundle('scss/app.scss', filters='scss', output='css/app.css')
assets.register('app_scss', scss)
#app.route('/')
def server_1():
r=1
g=2
b=3
i=g
if i == g:
with app.app_context():
print "Loading Template..."
rendered = flask.render_template('server_1.html', green=True)
print "Success! Template was loaded with green server status..."
time.sleep(5)
if __name__ == '__main__':
app.run(port=5000, debug=True)

You can do it by binding your application as the current application. Then you can use render_template() to render a template from your template directory, or render_template_string() to render directly from a template stored in a string:
import flask
app = flask.Flask('my app')
with app.app_context():
context = {'name': 'bob', 'age': 22}
rendered = flask.render_template('index.html', **context)
with app.app_context():
template = '{{ name }} is {{ age }} years old.'
context = {'name': 'bob', 'age': 22}
rendered = flask.render_template_string(template, **context)
Alternatively you could bypass Flask and go directly to Jinja2:
import jinja2
template = jinja2.Template('{{ name }} is {{ age }} years old.')
rendered = template.render(name='Ginger', age=10)
Update
It appears that you might be wanting to stream content back to the requesting client. If so you could write a generator. Something like this might work:
import time
from flask import Flask, Response, render_template_string
from flask import stream_with_context
app = Flask(__name__)
#app.route("/")
def server_1():
def generate_output():
age = 0
template = '<p>{{ name }} is {{ age }} seconds old.</p>'
context = {'name': 'bob'}
while True:
context['age'] = age
yield render_template_string(template, **context)
time.sleep(5)
age += 5
return Response(stream_with_context(generate_output()))
app.run()
Here is some documentation on streaming with Flask.

Related

Why is Flask making me put #app.route("/interior.html") in route instead of #app.route("/interior")

I am building a website with a booking page that requires me to put the data into a database so I am using python Flask app.
I know that in the #app.route I am only supposed to put #app.route("/exterior") however, whenever I try it using this method I get 404 Page Not Found. Instead I have to put #app.route("/exterior.html"). This is the only way it will work. I believe I have all the correct libraries and I have defined everything correctly; but, it only works if I put .html in the #app.route.
I have researched #app.routes and it only tells me the correct method which I know is #app.route("/exterior"); however, the only thing that works is #app.route("/exterior.html"). If anyone can tell me why this is happening that would be appreciated.
Here is my code.
import os
from cs50 import SQL
from flask import Flask, flash, jsonify, redirect, render_template, request, session
from datetime import datetime
# Configure application - turn this file into a Flask application -
app = Flask(__name__)
# Ensure templates are auto-reloaded -
app.config["TEMPLATES_AUTO_RELOAD"] = True
# Configure CS50 Library to use SQLite database
db = SQL("sqlite:///bookings.db")
#app.after_request
def after_request(response):
"""Ensure responses aren't cached"""
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
#app.route("/")
def index():
return render_template("/index.html")
#app.route("/index.html")
def indexpage():
return render_template("/index.html")
#app.route("/exterior.html")
def exterior():
return render_template("exterior.html")
#app.route("/interior")
def interior():
return render_template("interior.html")
if __name__ == 'main':
app.run(debug = True)
As you can see this is resulting me having to use two routes to load my index page. Once for when I initially run flask and again, so I am able to link to the pages in my navbar.
It's also not the correct method and it bothers me that I am not able to do it correctly. Please advise.
Here is my file directory:
project
static
pics
styles.css
templates
index.html
interior.html
exterior.html
about.html
gallery.html
layout.html
booknow.html
app.py
bookings.db
README.md
unsure why app.py and bookings are not before static and templates and alphabetically that would make more sense; however, this is how it is displayed.
I copied your code and made some minor syntax fixes. below is working as normal. perhaps you could copy this and start adding back some of your functionality and see where it goes wrong.
here is the directory structure:
test_app/
app.py
templates/
interior.html
exterior.html
index.html
and here is app.py:
import os
# from cs50 import SQL
from flask import Flask, flash, jsonify, redirect, render_template, request, session
from datetime import datetime
# Configure application - turn this file into a Flask application -
app = Flask(__name__)
# Ensure templates are auto-reloaded -
app.config["TEMPLATES_AUTO_RELOAD"] = True
# Configure CS50 Library to use SQLite database
# db = SQL("sqlite:///bookings.db")
#app.after_request
def after_request(response):
"""Ensure responses aren't cached"""
response.headers["Cache-Control"] = "no-cache, no-store, must-revalidate"
response.headers["Expires"] = 0
response.headers["Pragma"] = "no-cache"
return response
#app.route("/")
def index():
return render_template("index.html")
#app.route("/index/")
def indexpage():
return render_template("index.html")
#app.route("/exterior/")
def exterior():
return render_template("exterior.html")
#app.route("/interior/")
def interior():
return render_template("interior.html")
if __name__ == '__main__':
app.run(debug = True)
this work normally for me. what about you?

Obtain CSRF-Token and assign to variable

I want to obtain csrf-token provided by flask-wtf and assign it to a variable for future use with my flask app architecture. There's a way to either render it with hidden field {{ form.csrf_token }} or via csrf_token() for jinja. But docs do not mention how to achieve, say, the following:
from flask import Flask, jsonify
from flask_wtf.csrf import CSRFProtect
app = Flask(__name__)
app.secret_key = 'secret'
csrf = CSRFProtect(app)
#app.route('/api/get/endpoint_which_returns_json/', methods=['GET'])
def api():
csrf_token = # ??? what belongs here ???
return jsonify({'token': csrf_token})
if __name__ == '__main__':
app.run(debug=True)
How to achieve that? Thank you in advance.
When you use {{ form.csrf_token }} or {{ csrf_token() }} in your templates through Flask-WTF, they are just calling the flask_wtf.csrf.generate_csrf() function. You can import that and call it yourself to generate a token inside your view:
from flask_wtf.csrf import generate_csrf
#app.route('/', methods=['GET'])
def api():
return jsonify({'token': generate_csrf()})
I'm assuming the idea here is that the api client would be responsible for returning the token with POST requests to your other api resources? If you are just generating the token server-side so as to be able to validate forms that would otherwise require it, you may as well just disable CSRF protection.

Send data to html page through python

I have a python-flask app. And my source.py :
from flask import Flask, flash, redirect, render_template, request, session, abort
import os
from Modules.registry_bend.DockerImageReceiver import http_requester_v2_catalog, read_configurations
app = Flask(__name__)
#app.route('/v1')
def display_index():
return render_template('index.html')
if __name__ == "__main__":
# http_requester_v2_catalog("192.168.1.7", 5000)
app.secret_key = os.urandom(12)
app.run(debug=True, host='0.0.0.0', port=3150)
I run this source.py, and then open the browser and hit localhost:5000/v1.Then index.html appears. So, the challenge is, that a few seconds later I get some data, and I want to add them to index.html. How could it be possible? I have already called index.html once.
You can send the dynamic data to your HTML by sending context variables through the render template method.
flask.render_template(template_name_or_list, **context)
Renders a template from the template folder with the given context.
Parameters:
template_name_or_list – the name of the template to be rendered, or an iterable with template names the first one existing will be rendered
context – the variables that should be available in the context of the template.
Example -
return render_template('index.html', variable1=random.random(), variable2=random.random())
And in your HTML code you need to include these flask variables.
Example -
<p> {{variable1}} </p>
<p> {{variable2}} </p>
And whenever you refresh you html page in your browser. The new data will be displayed.

How to pass arbitrary arguments to a flask blueprint?

I have a flask api which I have wrapped up in an object. Doing this has made unit testing a breeze, because I can instantiate the api with a variety of different settings depending on whether it is in production, test, or whatehaveyou.
I am now trying to extend the api a bit, and for that I'm using a blueprint. The problem is that I cannot figure out how to pass arguments to the blueprint. My routes require information like which database to access, and that information is not static. How can I pass this information into a blueprint? I have included code below as an example:
api.py:
class MyApi(object):
def __init__(self, databaseURI):
self.app = Flask(__name__)
self.app.register_blueprint(myblueprint)
blueprint.py
myblueprint= Blueprint('myblueprint', __name__)
#myblueprint.route('/route', methods=['GET'])
def route():
database = OpenDatabaseConnection(databaseURI)
There is a related question here:
How do I pass constructor arguments to a Flask Blueprint?
But the people who answer the question solve the op's use-case specific problem without actually answering the question of how to pass arbitrary arguments to a blueprint.
You could create the blueprint dynamically in a constructor function:
def construct_blueprint(database):
myblueprint = Blueprint('myblueprint', __name__)
#myblueprint.route('/route', methods=['GET'])
def route():
database = database
return(myblueprint)
Use Flask config system (app.config) to store all your config data, then from your Blueprint read your Application Context using current_app.
Store in app.config:
app.config[DATABASE_URI] = databaseURI
Read application context:
databaseURI = current_app.config[DATABASE_URI]
Sample code
main.py
from flask import Flask
from blueprint import myblueprint
app = Flask(__name__)
app.register_blueprint(myblueprint)
app.config[DATABASE_URI] = databaseURI
blueprint.py
from flask import current_app
myblueprint= Blueprint('myblueprint', __name__)
#myblueprint.route('/route', methods=['GET'])
def route():
databaseURI = current_app.config[DATABASE_URI]
database = OpenDatabaseConnection(databaseURI)
This way it's possible to add a blueprint, passing parameters, inside an appfactory. Sometimes you'll need it and it's not described anywhere in the flask docs.
Assuming bp1.py, bp2.py are in the same folder as your appname
from appname import bp1, bp2
app.register_blueprint(bp1.bp)
# with parameters:
app.register_blueprint(bp2.construct_blueprint(arg1, arg2))
inside bp2.py:
def construct_blueprint(arg1, arg2):
bp = Blueprint("bp2", __name__)
#bp.route('/test')
def test():
ret = {'arg1': arg1, 'arg2': arg2}
return jsonify(ret)
return bp
I went about this in a slightly different way by creating a class in the helper blueprints python files. This way I can have one call to load the class and then pass the result to the blueprint function in the main python script. When I load the class I can pass any attributes I've configured. I like this approach as it keeps my code much cleaner.
The code I've put in here can also be found at https://github.com/dacoburn/example-flask-blueprints if you want to download it. I added comments to the github with more details of what is going on in the python files.
The folder structure I have is:
src
|___main.py
|___routes
|___index.py
|___example.py
|___templates
|___index.html
|___example.html
main.py
from flask import Flask
import os
from routes.index import Index
from routes.example import Example
app = Flask(__name__)
index = Index("Example User")
example = Example("Random Arg")
app.register_blueprint(index.index)
app.register_blueprint(example.example)
if __name__ == '__main__':
port = int(os.environ.get('APP_PORT', 5000))
app.run(host='0.0.0.0', port=port, debug=True)
index.py
from flask import render_template, Blueprint
class Index:
def __init__(self, username):
self.username = username
self.index = self.create_index()
def create_index(self):
index_page = Blueprint("index", __name__)
#index_page.route("/", methods=['GET'])
def index():
return render_template("index.html", username=self.username)
return index_page
example.py
from flask import render_template, Blueprint
class Example:
def __init__(self, arg):
self.arg = arg
self.example = self.create_example()
def create_example(self):
example_page = Blueprint("example", __name__)
#example_page.route("/<username>", methods=['GET'])
def example(username):
return render_template("example.html",
username=username,
arg=self.arg)
return example_page
index.html
<html>
<head>
<title>Example Page</title>
</head>
<body>
<p>Hello {{ username }}</p>
<br>
This page also has a redirect to another route:
<ul>
<li>Example Page</li>
</ul>
</body>
</html>
example.html
<html>
<head>
<title>Example Page 2</title>
</head>
<body>
<p>Hello {{ username }}</p>
<br>
Here is the random argument: {{ arg }}
<br>
<br>
This page also has a link to the main page:
<ul>
<li>Index Page</li>
</ul>
</body>
</html>

Split Python Flask-Menu app into multiple files

As an extension of this question Split Python Flask app into multiple files
I want to use Flask-Menu and have each separate menu page in it's own Python file.
Here is my main site main.py file this has the /first menu item
from flask import Flask, render_template, Blueprint, abort
from flask_wtf import Form
from flask.ext import menu
from wtforms import HiddenField
from second import bp_second
class EmptyForm(Form):
hidden_field = HiddenField('You cannot see this', description='Nope')
def create_app(configfile=None):
app = Flask(__name__)
app.register_blueprint(bp_second)
menu.Menu(app=app)
#app.route('/')
#menu.register_menu(app, '.', 'Home')
def index():
form = EmptyForm()
form.validate_on_submit()
return render_template('index.html', form=form)
#app.route('/first')
#menu.register_menu(app, '.first', 'First', order=0)
def first():
form = EmptyForm()
form.validate_on_submit()
return render_template('index.html', form=form)
return app
if __name__ == '__main__':
create_app().run(debug=True)
I have a menu item called second.py here this has the /second menu item
from flask import Blueprint, render_template
from flask_wtf import Form
from flask.ext import menu
from wtforms import TextField
class TextForm(Form):
text = TextField(u'text', [validators.Length(min=2, max=5, message="my item")])
bp_second = Blueprint('second', __name__, url_prefix='/second')
#bp_second.route("/second")
#menu.register_menu(bp_second, '.second', 'Second', order=1)
def second():
form = TickerForm()
form.validate_on_submit() #to get error messages to the browser
return render_template('index.html', form=form)
How ever when I click the menu item for /second I get a "GET /meta HTTP/1.1" 404 - message. The / and /first menu items work
I suspect, that your route is wrong. As I read it your route for second is /second/second so your menu entry should be
#menu.register_menu(bp_second, '.second.second', 'Second', order=1)
You can check the Flask-Menu documentation about Blueprints Support in Flask-Menu

Categories

Resources