Flask

A micro web development framework in Python

TrojanHacks Fall 2014

Setup

Installing Python 

Both version 2.6+ or 3.3+ works 

www.python.org

Install and Setup VirtualEnv

http://flask.pocoo.org/docs/0.10/installation/

First get VirtualEnv...

Setup VirtualEnv...

virtualenv venv

Activate VirtualEnv...

Mac OS / Linux:

Windows:

. venv/bin/activate
venv\scripts\activate

Install Flask

pip install Flask

http://flask.pocoo.org/

Hello World!

Starting simple...

Code

In a file named 'app.py':

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

Running the App

$ python app.py 

Type in terminal...

And you should see...

* Running on http://127.0.0.1:5000/

Code

In a file named 'app.py':

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

Code

from flask import Flask
app = Flask(__name__)

In a file named 'app.py':

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

Defines it to be a Flask Application!

Code

In a file named 'app.py':

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

Defines a route!

Code

In a file named 'app.py':

from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello World!'

if __name__ == '__main__':
    app.run()

Tells python where to start execution!

Basic Routing

Hello #Your Name Here#!

@app.route("/hello/")
def hello():
  return "Hello World!"


@app.route("/hello/<name>")
def hello_name(name):
  return "Hello %s!" % name

HTML files?

Need to create the following directories...

/static - For CSS/JS/Images
/templates - For HTML files
from flask import render_template

 Need to add a new import...

 and a new route...

@app.route("/")
def index():
  return render_template("index.html")

CSS files?

Need to add another import...

And change the link to the stylesheet...

<link rel="stylesheet" href=
"{{ url_for('static', filename='css/kube.min.css') }}" />
from flask import url_for

Do the same for the about yourself page.

Now...

  • Add a new page for about
  • Create a link from home to about
  • and about back to home in nav bar

Templates

and Layouts

DRY -- Don't Repeat Yourself

Move common code into a layout.html file.

index.html can now look like this...

{% extends "layout.html" %}

{% block body %}
   <h1>Home Page</h1>
{% endblock %}

{% block body %}{% endblock %}

Place the following where the content of your page should be

Conditional Page Content

{% extends "layout.html" %}

{% block body %}
  {% if name %}
    <h1>Hello {{ name }}!</h1>
  {% else %}
    <h1>Hello World!</h1>
  {% endif %}
{% endblock %}

In a new file called 'hello.html':

Conditional Page Content

@app.route("/hello_page/")
@app.route("/hello_page/<name>")
def hello_page(name=None):
  return render_template("hello.html", name=name);

And in app.py...

HTTP Methods

GET vs POST

By default, all routes are GET

To change it to a POST...

@app.route("/post_route", methods=["POST"])

One URL, Two Methods

@app.route("/http", methods=['POST', 'GET'])
def http_demo():
  if request.method == 'POST':
    return "POST Request"
  else:
    return "GET Request"

Databases

Now to the more difficult part...

SQLite

http://www.sqlite.org/

First, install...

Configuring App

First an import to the top:

import sqlite3

Add some configuration data:

DATABASE = "/tmp/todo.db"
DEBUG = True
SECRET_KEY = ""
USERNAME = "admin"
PASSWORD = "default"

Then, after app = Flask(__name__), add:

app.config.from_object(__name__)

Setting up the Schema

drop table if exists tasks;

Set the structure for our todo list in 'schema.sql':

create table tasks (
  id integer primary key autoincrement,
  name text not null
);

Delete the existing tasks table...

Create a new tasks table...

Connect to Database

def connect_db():
  return sqlite3.connect(app.config["DATABASE"])

Initialize the DB

In the terminal:

sqlite3 /tmp/todo.db < schema.sql

-- OR --

The suggestion to create a init_db function:

http://flask.pocoo.org/docs/0.10/tutorial/dbinit/#tutorial-dbinit

Request DB Preparation

@app.before_request
def before_request():
    g.db = connect_db()

@app.teardown_request
def teardown_request(exception):
    db = getattr(g, 'db', None)
    if db is not None:
        db.close()

Show TODOs

First, some new imports...

from flask import g
@app.route("/todo")
def todo_show():
  cur = g.db.execute('select id, name from tasks')
  tasks = [dict(tid=row[0], name=row[1]) for row in cur.fetchall()]
  return render_template('todo.html', tasks=tasks)
select id, name from tasks

The SQL statement being called...

The TODO show route...

Show TODOs

Now the html...

{% extends "layout.html" %}

{% block body %}

  <ul class=entries>
    {% for task in tasks %}
      <li><h2>{{ task.name }}</h2>
    {% else %}
      <li><em>WOOHOO!.  No todos here so far</em>
    {% endfor %}
  </ul>
{% endblock %}

Add a TODO

Create new routes...

@app.route("/todo/new")
def todo_new():
  return render_template("new_todo.html")

@app.route("/todo/add", methods=["POST"])
def todo_add():
  g.db.execute('insert into tasks (name) values (?)', [request.form['task']])
  g.db.commit()
  return redirect(url_for('todo_show'))

The Add SQL statement:

insert into tasks (name) values (name)

New imports...

from flask import redirect

Removing a TODO

@app.route("/todo/remove/<int:tid>")
def todo_remove(tid):
  sql_command = "delete from tasks where id=%d" % tid
  g.db.execute(sql_command)
  g.db.commit()
  return redirect(url_for('todo_show'))

disclaimer: This really should be a POST... but its 5am...

New Route:

SQL statement:

delete from tasks where id = tid

THE END

Congratulations, you have made a Flask Application.

Suggested resources:

http://flask.pocoo.org/docs/0.10/tutorial/

http://www.w3schools.com/sql/default.asp

Made with Slides.com