Flaskr: Tutorial with extra comments
Here is the Flask tutorial file with extra commenting:
import sqlite3
from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
from contextlib import closing
# configuration
DATABASE = 'flaskr.db'
# DEBUG must be set to False in production or interactive debugger can be used
DEBUG = True
# SECRET_KEY keeps client sessions secure (e.g. to sign cookies). It should be set to a complex random value.
# the following code can be used to generate a good key:
# >>> import os, base64
# >>> base64.urlsafe_b64encode(os.urandom(30))
SECRET_KEY = 'development key'
USERNAME = 'admin'
PASSWORD = 'default'
app = Flask(__name__)
# from_object will look at the given object and look for all UPPERCASE variables (e.g. DATABASE, DEBUG)
# you can force Flask top use a configuration file based on the environment using:
# app.config.from_envvar('FLASKR_SETTINGS", silent=True)
# this will make Flask read an environmental variable containing the location of the settings file.
# the silent=True ensures that no complaint is made if the variable is missing - Flask will then use the defaults.
app.config.from_object(__name__)
def connect_db():
return sqlite3.connect(app.config['DATABASE'])
# This function initialises the database and creates the tables within the sql file
def init_db():
# http://docs.python.org/dev/library/contextlib.html#contextlib.closing
# closing() ensures that the connection remains open for the duration of the with block.
with closing(connect_db()) as db:
# app.open_resources opens one of the resources from the application's folder (e.g. /static/picture.jpg)
with app.open_resource('schema.sql') as f:
db.cursor().executescript(f.read())
db.commit()
# the before_request() will always be called before a database connection
@app.before_request
def before_request():
# g is a special object provided by Flask that stores information from one request only.
g.db = connect_db()
# teardown_request() gets called after reponse has been constructed - will always be called after exception
# after_request() can also be used, but is not guaranteed to be called when an exception is raised.
@app.teardown_request
def teardown_request(exception):
g.db.close()
# app.route tells flask what url should trigger the function
# it can be made to accept parameters:
# >>> app.route('/user/')
# --> return username
# Or:
# >>> app.route('/post/') # or float or path (allows slashes)
# --> return post_id
@app.route('/')
def show_entries():
# this will return entries as tuples
# to convert to a dictionary instead: http://flask.pocoo.org/docs/patterns/sqlite3/#easy-querying
cur = g.db.execute('select title, text from entries order by id desc')
entries = [dict(title=row[0], text=row[1]) for row in cur.fetchall()]
return render_template('show_entries.html', entries = entries)
# the methods parameter ensures that only certain requests are processed - in this example, only POST requests.
@app.route('/add', methods=['POST'])
def add_entry():
if not session.get('logged_in'):
abort(401)
# always use question marks to stop the ability to use SQL injection
g.db.execute('insert into entries (title, text) values (?, ?)',
[request.form['title'], request.form['text']])
g.db.commit()
# the flash() allows a message to be recorded and accessed in the next request:
# http://flask.pocoo.org/docs/patterns/flashing/
flash('New entry was successfully posted')
return redirect(url_for('show_entries'))
@app.route('/login', methods=['GET', 'POST'])
def login():
error = None
if request.method == 'POST':
if request.form['username'] != app.config['USERNAME']:
error = 'Invalid username'
elif request.form['password'] != app.config['PASSWORD']:
error = 'Invalid password'
else:
# sessions back it possible to remember information between requests by using a signed cookie.
# for more about sessions - http://flask.pocoo.org/docs/api/#sessions
session['logged_in'] = True
flash('You were logged in')
# flask.redirect(location, code=302) redirects client to a target location - supports codes 301,303,305,307
# url_for(endpoint) generates a url to the given endpoint
# see http://flask.pocoo.org/docs/quickstart/#url-building
return redirect(url_for('show_entries'))
# render_template(template_name_or_list, **context) renders a template from the templates folder.
# see http://flask.pocoo.org/docs/api/#template-rendering
# for more on Jinja2 in flask, see http://flask.pocoo.org/docs/templating/
# also http://jinja.pocoo.org/docs/templates/
return render_template('login.html', error=error)
@app.route('/logout')
def logout():
# the dictionary pop() with the second parameter as "None" deleted the key from the dictionary.
# if there's nothing there, nothing happens --> don't have to ensure that a user is already logged-in.
session.pop('logged_in', None)
flash('You were logged out')
return redirect(url_for('show_entries'))
if __name__ == '__main__':
app.run()
Additionally, here is the layout.html file with extra commenting:
Flaskr
Flaskr
{% for message in get_flashed_messages() %}
{{ message }}
{% endfor %}
{% block body %}{% endblock %}