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
- methods with
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
- HTML request data
- 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