Flask for beginners

Tehran PyCon 2017

What we will learn

  • Setting up a VirtualEnv
  • Basic concepts of HTTP and REST API
  • Step by step Flask implementation

Resources

  • Slides: https://slides.com/kianpeymani/flask-for-beginners
  • Github: https://github.com/Kianenigma/FlaskForBeginners-PyCon2017

python packages

  • Python owes its success highly to its active community
  • Command line tool: PIP
    • pip is a recursive acronym that can stand for either "Pip Installs Packages" or "Pip Installs Python"
  • Hosted in PyPI
    • The Python Package Index is a repository of software for the Python programming language. There are currently 98912 packages here.
    • the growth rate is ~71 package/day

Virtual envoronmetn

  • Avoid dependency hell 
    • project X depends on foo lib version Y
    • project Y depends on foo lib version Y.1
    • project X will not work with Y.1 due to API changes
  • Protect OS python
  • Python 2 / Python 3 conflicts

Virtual envoronmetn

python 2

#install virtualenv using pip
pip install virtualenv

# choose a folder
cd my_project_folder

# create the venv
virtualenv venv

# active it
source venv/bin/activate

Virtual envoronmetn

python 3

python3 -m venv /path/to/env

cd path/to/env

source /venv/bin/activate

The venv package is built-in

Virtual envoronmetn

setting up for this tutorial

source ./venv/bin/activate 

pip install flask

Switch from os python to venv

web and http

http messages

  • ​are ONLY plain text messages
  • contain a body and a header (+ path)
    • ​the body can be ANY text data
    • headers have a standard

hello wor... flask

commit #1 

#learning-flask/app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'aleyk'

app.run(debug=True)

hello wor... flask

cool. let's make it do something real

#learning-flask/app.py

from flask import Flask

app = Flask(__name__)

@app.route('/')
def hello():
    return 'aleyk'

@app.route('/foo')
def foo(): 
    return 'foo'

@app.route('/bar')
def bar(): 
    return 'bar'

def aHelperFunction(): 
    return 'some stuff'

@app.route('/baz')
def baz(): 
    return 'baz'

def databaseConnection(): 
    return DB()

def fetchObjects(): 
    return databaseConnection().getObjects()

app.run(debug=True)

hello wor... flask

hello wor... flask

basic application

commit #2 

  • our app: 
    • methods with
      • @app.route() 
    • will need to render views
    • will need to serve static content

basic application

commit #2 

  • Let's 
    • isolate the app `app` variable in a package
    • create a specific file for all of the routes
    • specific folder for static files and tamplates

basic application

isolated package for app

# learning-flask/app/__init__.py
from flask import Flask

app = Flask(__name__)

# think of it as a way of executing `views.py`
from app import views

basic application

isolated routes file

# learning-flask/app/views.py

from app import app

@app.route('/')
@app.route('/index')
def index():
    return "Hello flask"

basic application

run script

# learning-flask/run.py

from app import app
app.run(debug=True)

templates and html

commit #3.1 

  • Returning a plain text as response is not that cool

templates and html

commit #3.1

@app.route('/user')
def user():
    user = {'name': 'kian'}
    return '''
<html>
  <head>
    <title>PyCon</title>
  </head>
  <body>
    <h1>Hello, ''' + user['name'] + '''</h1>
  </body>
</html>
'''

templates and html

commit #3.1

templates and html

commit #3.1

from flask import render_template


@app.route('/user-template')
def user_template():
    user = {'name': 'kian'}
    title = 'PyCon'
    return render_template('user.html', user=user, title=title)

templates and html

commit #3.1

<!-- templates/user.html -->
<html>
  <head>
    <title>{{ title }}</title>
  </head>
  <body>
      <h1>Hello, {{ user.name }}</h1>
  </body>
</html>

MORE ON TEMPLATES

commit #3.2 

  • Conditional statements
  • Iterations
  • etc ...

MORE ON TEMPLATES

commit #3.2 

@app.route('/user-template')
def user_template():
    user = {'name': 'kian'}
    title = 'PyCon'
    posts = [
        {
            'author': user,
            'body': 'a mock post'
        },
        {
            'author': user,
            'body': 'another mock post'
        }
    ]
    return render_template('user.html',
    user=user,
    title=title,
    posts=posts)

MORE ON TEMPLATES

commit #3.2 

{% if title %}
  <title>{{ title }}</title>
  {% else %}
  <title>Default</title>
{% endif %}


{% for post in posts %}
  <div>
    <p>{{ post.author.name }} says: <b>{{ post.body }}</b></p>
  </div>
{% endfor %}

layout and template import

commit #3.3

  • Assume we want to have a HTML file for each page
    • each page has a fix header and footer

Agenda:

  • Reduce redundant code in HTML
  • Organized structure
  • Unified style

layout and template import

commit #3.3

<body>
  <div class="jumbotron" style="margin: 20px; padding:20px;">
    <a href="/"> Home </a> -
    <a href="/user"> User </a> - 
    <a href="/user-template"> User-template </a>
  </div>
  <div class="container">
    <hr>
    {% block content %}{% endblock %}
  </div>
</body>

Master layout file

layout and template import

commit #3.3

{% extends "layout.html" %}
{% block content %}
  <h1>Hello, {{ user.name }}</h1>
  {% for post in posts %}
  <div>
    <p>{{ post.author.name }} says: <b>{{ post.body }}</b></p>
  </div>
  {% endfor %}
{% endblock %}

Normal view file

request and response

  • a method in web server can receive data via
    • HTML request data
      • HTML Form 
      • Ajax request
    • URL parameters / query strings
    • various socket types
  • a method can respond with 
    • an HTML content (we've already seen this one)
    • a redirect (via HTTP header: location)
    • data
      • JSON
      • XML
      • Plain text or basically any other text data

request and response - under the hood

commit #4.1

from flask import request

@app.route('/login', methods=['GET', 'POST'])
def login():
    print('request',request)
    print('method', request.method)
    print('form', request.form)
    print('args', request.args)
    return render_template('login.html')

request and response - under the hood

commit #4.1

<form action="/login" method="post">
  <div class="form-group">
    <input type="text" name="username">
  </div>

  <div class="form-group">
    <input type="password" name="password">
  </div>

  <input type="submit" value="Submit">

</form>

request and response

commit #4.1 - QUERY PARAMETERS

Let's try and fill in the page with a

?foo=bar&bar=baz

appended to the url

request and response

commit #4.2 - AJAX

<button type="button" name="button" id="ajax"> Send AJAX </button>

$("#ajax").click(function(e) {
  $.post('/login', {foo: 'bar', data: 1}, function(data){
    console.log(data)
  })
})

Flask for beginners - PyCon 2017

By Kian Peymani

Flask for beginners - PyCon 2017

Video Link: http://takhtesefid.org/watch?v=12570870265

  • 736