Difference between revisions of "Parts of a Flask Web App"
(→Handling HTML Forms) |
(→Templates) |
||
(10 intermediate revisions by the same user not shown) | |||
Line 37: | Line 37: | ||
=url_for= | =url_for= | ||
+ | You will need to add url_for to the Flask import: | ||
+ | |||
+ | <syntaxhighlight lang=python> | ||
+ | from flask import Flask, url_for | ||
+ | </syntaxhighlight> | ||
+ | |||
If you look at this example: | If you look at this example: | ||
Line 65: | Line 71: | ||
You will need to add request to the Flask import: | You will need to add request to the Flask import: | ||
+ | <syntaxhighlight lang=python> | ||
+ | from flask import Flask, request | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The code below is an example of using html form elements, it is for a login page which produces the form initially. Clicking the login button will cause a submit and therefore 'POST' will be set, it then checks the form data: | ||
− | |||
<syntaxhighlight lang=python> | <syntaxhighlight lang=python> | ||
@app.route('/login', methods=['GET', 'POST']) | @app.route('/login', methods=['GET', 'POST']) | ||
Line 72: | Line 82: | ||
if request.method == 'POST': | if request.method == 'POST': | ||
if (request.form['username']=="wayne") and request.form['password']=="pass": | if (request.form['username']=="wayne") and request.form['password']=="pass": | ||
− | return redirect(url_for('home')) | + | return redirect(url_for('home')) # will need to add redirect to the Flask import |
return ''' | return ''' | ||
<form method="post"><p> | <form method="post"><p> | ||
Line 87: | Line 97: | ||
=Using Sessions= | =Using Sessions= | ||
+ | In order to use session, you will need to include it in the Flask import and you must set a secret_key on the app: | ||
+ | |||
+ | <syntaxhighlight lang=python> | ||
+ | from flask import Flask, session, redirect, url_for, request | ||
+ | |||
+ | app = Flask(__name__) | ||
+ | |||
+ | # Set the secret key to some random bytes. Keep this really secret! | ||
+ | # use: import os and then: print(os.urandom(16)) to generate a suitable key | ||
+ | app.secret_key = b'_5#y2L"F4Q8z\n\xec]/' | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | You can generate a new suitable string using: | ||
+ | |||
+ | <syntaxhighlight lang=python> | ||
+ | import os | ||
+ | print(os.urandom(16)) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | Now the individual routes and methods: | ||
+ | |||
+ | <syntaxhighlight lang=python> | ||
+ | @app.route('/') | ||
+ | def index(): | ||
+ | if 'username' in session: | ||
+ | return 'Logged in as ' + session['username'] | ||
+ | return 'You are not logged in' | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The method above checks if username is set as a session variable, if it is the code displays a message including the username. Otherwise it displays the message to say you aren't logged in. | ||
+ | |||
+ | <syntaxhighlight lang=python> | ||
+ | @app.route('/login', methods=['GET', 'POST']) | ||
+ | def login(): | ||
+ | if request.method == 'POST': | ||
+ | if (request.form['username']=="wayne") and request.form['password']=="pass": | ||
+ | session['username'] = request.form['username'] | ||
+ | return redirect(url_for('index')) | ||
+ | return ''' | ||
+ | <form method="post"> | ||
+ | <p>Username: <input type=text name=username></p> | ||
+ | <p>Password: <input type=password name=password></p> | ||
+ | <input type=submit value=Login> | ||
+ | </form> | ||
+ | ''' | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The method above checks if the submit button was clicked, it checks the username and password and ten sets the username session variable. | ||
+ | |||
+ | <syntaxhighlight lang=python> | ||
+ | |||
+ | @app.route('/logout') | ||
+ | def logout(): | ||
+ | # remove the username from the session if it's there | ||
+ | session.pop('username', None) | ||
+ | return redirect(url_for('index')) | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | This method will remove the username session variable. | ||
=Templates= | =Templates= | ||
+ | I created my flask app using visual studio, and this already implements templates in your web app. But to use templates you need to create a template folder within the root folder of your app (ie the folder with your 'views.py' and '__init__.py'): | ||
+ | |||
+ | [[File:Flask template folder.gif]] | ||
+ | |||
+ | Now in this folder use this code to create a file called 'layout.html': | ||
+ | |||
+ | <syntaxhighlight lang=html> | ||
+ | <!DOCTYPE html> | ||
+ | <html> | ||
+ | <head> | ||
+ | <meta charset="utf-8" /> | ||
+ | <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
+ | <title>{{ title }} - My Flask Application</title> | ||
+ | <link rel="stylesheet" type="text/css" href="/static/content/bootstrap.min.css" /> | ||
+ | <link rel="stylesheet" type="text/css" href="/static/content/site.css" /> | ||
+ | <script src="/static/scripts/modernizr-2.6.2.js"></script> | ||
+ | </head> | ||
+ | |||
+ | <body> | ||
+ | <div class="navbar navbar-inverse navbar-fixed-top"> | ||
+ | <div class="container"> | ||
+ | <div class="navbar-header"> | ||
+ | <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"> | ||
+ | <span class="icon-bar"></span> | ||
+ | <span class="icon-bar"></span> | ||
+ | <span class="icon-bar"></span> | ||
+ | </button> | ||
+ | <a href="/" class="navbar-brand">Application name</a> | ||
+ | </div> | ||
+ | <div class="navbar-collapse collapse"> | ||
+ | <ul class="nav navbar-nav"> | ||
+ | <li><a href="{{ url_for('home') }}">Home</a></li> | ||
+ | <li><a href="">About</a></li> | ||
+ | <li><a href="">Contact</a></li> | ||
+ | </ul> | ||
+ | </div> | ||
+ | </div> | ||
+ | </div> | ||
+ | |||
+ | <div class="container body-content"> | ||
+ | {% block content %}{% endblock %} | ||
+ | <hr /> | ||
+ | <footer> | ||
+ | <p>© {{ year }} - My Flask Application</p> | ||
+ | </footer> | ||
+ | </div> | ||
+ | |||
+ | <script src="/static/scripts/jquery-1.10.2.js"></script> | ||
+ | <script src="/static/scripts/bootstrap.js"></script> | ||
+ | <script src="/static/scripts/respond.js"></script> | ||
+ | {% block scripts %}{% endblock %} | ||
+ | |||
+ | </body> | ||
+ | </html> | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | The code above creates the key interface items such as the navigation, the key section is a 'block' called 'content'. '{{ year }}' will be passed into the template to display the correct copyright year. Now create a second file called 'index.html' and add the following code: | ||
+ | |||
+ | <syntaxhighlight lang=html> | ||
+ | {% extends "layout.html" %} | ||
+ | |||
+ | {% block content %} | ||
+ | |||
+ | <div class="jumbotron"> | ||
+ | <h1>My Title</h1> | ||
+ | <p class="lead">My content</p> | ||
+ | <p>Even more content</p> | ||
+ | </div> | ||
+ | |||
+ | {% endblock %} | ||
+ | </syntaxhighlight> | ||
+ | |||
+ | This code will load the 'layout.html' template, and because it defines the 'content' block this will be inserted into the main template. Now we can make all this work by making the 'home' route render the template: | ||
+ | |||
+ | <syntaxhighlight lang=python> | ||
+ | @app.route('/') | ||
+ | @app.route('/home') | ||
+ | def home(): | ||
+ | """Renders the home page.""" | ||
+ | return render_template('index.html', title='Home Page', year=datetime.now().year) | ||
+ | </syntaxhighlight> |
Latest revision as of 16:15, 2 November 2019
@app.route
This defines where a particular path in the url relates too:
@app.route("/")
def hello():
return "Hello World!"
When the app server is running, visiting the root will produce the message 'Hello World!'. The code below will also display this if you visit '/home' on the app server:
@app.route("/")
@app.route("/home")
def hello():
return "Hello World!"
Parameters
The example below will just display the message:
@app.route("/")
def hello():
return "Hello World!"
You can also use parameters:
@app.route("/<name>")
def hello(name):
return "Hello "+name
Using this method the parameters are passed as strings, and you may need to convert them. In this example the URL '/Wayne' will display the message 'Hello Wayne'.
url_for
You will need to add url_for to the Flask import:
from flask import Flask, url_for
If you look at this example:
@app.route("/home")
def home():
return "test"
@app.route("/hello")
def hello():
return "Hello World!"
it creates 2 paths, one for '/hello' (runs 'def hello()') and one for '/home' (runs 'def home()'). url_for will accept the name of the method (ie def ....) and return the route.
so:
url_for('hello')
will return:
/hello
Handling HTML Forms
You will need to add request to the Flask import:
from flask import Flask, request
The code below is an example of using html form elements, it is for a login page which produces the form initially. Clicking the login button will cause a submit and therefore 'POST' will be set, it then checks the form data:
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
if (request.form['username']=="wayne") and request.form['password']=="pass":
return redirect(url_for('home')) # will need to add redirect to the Flask import
return '''
<form method="post"><p>
Username: <input type=text name=username><p>
Password: <input type=password name=password><p>
<input type=submit value=Login>
</form>
'''
The route must include', methods=['GET','POST']' this will allow it to accept data from an html form. This will use either, get (via the url) or post (via the http header).
Within the method you can check the request method (request.method=='POST'). You can then access data from the form using request.form['...'], the text in the square brackets needs to match the name of the form element from the html.
Using Sessions
In order to use session, you will need to include it in the Flask import and you must set a secret_key on the app:
from flask import Flask, session, redirect, url_for, request
app = Flask(__name__)
# Set the secret key to some random bytes. Keep this really secret!
# use: import os and then: print(os.urandom(16)) to generate a suitable key
app.secret_key = b'_5#y2L"F4Q8z\n\xec]/'
You can generate a new suitable string using:
import os
print(os.urandom(16))
Now the individual routes and methods:
@app.route('/')
def index():
if 'username' in session:
return 'Logged in as ' + session['username']
return 'You are not logged in'
The method above checks if username is set as a session variable, if it is the code displays a message including the username. Otherwise it displays the message to say you aren't logged in.
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
if (request.form['username']=="wayne") and request.form['password']=="pass":
session['username'] = request.form['username']
return redirect(url_for('index'))
return '''
<form method="post">
<p>Username: <input type=text name=username></p>
<p>Password: <input type=password name=password></p>
<input type=submit value=Login>
</form>
'''
The method above checks if the submit button was clicked, it checks the username and password and ten sets the username session variable.
@app.route('/logout')
def logout():
# remove the username from the session if it's there
session.pop('username', None)
return redirect(url_for('index'))
This method will remove the username session variable.
Templates
I created my flask app using visual studio, and this already implements templates in your web app. But to use templates you need to create a template folder within the root folder of your app (ie the folder with your 'views.py' and '__init__.py'):
Now in this folder use this code to create a file called 'layout.html':
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{ title }} - My Flask Application</title>
<link rel="stylesheet" type="text/css" href="/static/content/bootstrap.min.css" />
<link rel="stylesheet" type="text/css" href="/static/content/site.css" />
<script src="/static/scripts/modernizr-2.6.2.js"></script>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a href="/" class="navbar-brand">Application name</a>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li><a href="{{ url_for('home') }}">Home</a></li>
<li><a href="">About</a></li>
<li><a href="">Contact</a></li>
</ul>
</div>
</div>
</div>
<div class="container body-content">
{% block content %}{% endblock %}
<hr />
<footer>
<p>© {{ year }} - My Flask Application</p>
</footer>
</div>
<script src="/static/scripts/jquery-1.10.2.js"></script>
<script src="/static/scripts/bootstrap.js"></script>
<script src="/static/scripts/respond.js"></script>
{% block scripts %}{% endblock %}
</body>
</html>
The code above creates the key interface items such as the navigation, the key section is a 'block' called 'content'. 'Template:Year' will be passed into the template to display the correct copyright year. Now create a second file called 'index.html' and add the following code:
{% extends "layout.html" %}
{% block content %}
<div class="jumbotron">
<h1>My Title</h1>
<p class="lead">My content</p>
<p>Even more content</p>
</div>
{% endblock %}
This code will load the 'layout.html' template, and because it defines the 'content' block this will be inserted into the main template. Now we can make all this work by making the 'home' route render the template:
@app.route('/')
@app.route('/home')
def home():
"""Renders the home page."""
return render_template('index.html', title='Home Page', year=datetime.now().year)