Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Flask intro - ROSEdu web workshops
1. Flask intro
rosedu web workshops
27/03/2013 alex@grep.ro
alex@eftimie.ro
2. prerequisites what we'll do
● python ● set-up a working environment
● bash ● run a local server
● HTTP ● write a twitter clone in a single
python file
● use templates
● use an ORM
3. was ist flask?
● micro web framework
● WSGI (same as django, webapp2)
● decoupled
● werkzeug routing
● jinja2 templates
● wtf forms
● many extensions
● write web applications not web scripts (such as PHP does)
6. new message form
● create a file new.html inside a templates/ folder
<h1>New message </h1>
<form method="post">
<textarea rows="4" cols="80" name="message"></textarea>
<br>
<button type="submit">send</button>
</form>
● route /new to a view function rendering the template
...
return flask.render_template( 'new.html' )
(see home())
7. form submit; redirect
● check request method (one of 'GET' or 'POST')
flask.request.method == 'POST'
● get post data, print it
print flask.request.form['message']
● redirect to home page
flask.redirect(flask .url_for('home'))
@app.route('/new', methods=['GET', 'POST'])
def new():
if flask.request.method == 'POST':
print "msg:", flask.request.form['message']
return flask.redirect(flask.url_for('home'))
return flask.render_template('new.html')
8. db; message model
● in a terminal:
pip install SQLAlchemy Flask-SQLAlchemy
● in mini.py
from flask.ext.sqlalchemy import SQLAlchemy
...
app.config['SQLALCHEMY_DATABASE_URI' ] = 'sqlite:////tmp/test.db'
db = SQLAlchemy(app)
...
class Message(db.Model):
id = db.Column(db.Integer, primary_key =True)
text = db.Column(db.String)
time = db.Column(db.DateTime)
9. save to db
● create db before app.run()
db.create_all()
● replace print with insert statement, in new()
text = flask.request.form[ 'message']
message = Message(text =text, time =datetime.utcnow())
db.session.add(message)
db.session.commit()
● sqlite3 /tmp/test.db 'select * from message'
10. fetch from db
messages.html
● change print "Hello World" with
template rendering and context <h1>Mini Twitter </h1>
<p>
flask.render_template( 'messages. <a href="{{ url_for('new') }}" >new msg</a>
html', </p>
messages =Message.query.all())
{% for message in messages %}
<article>
● create html file in templates/ <p>{{ message.text }} </p>
<footer>
<time>{{message.time}} </time>
● use {{ variable }} to display </footer>
</article>
variable value in template {% endfor %}
● call url_for for view permalink
● use {% for %} to iterate through
messages
11. template filters
Usage: You:
{{ variable |filter }} ● display message time in local
time
Custom:
@app.template_filter()
def tolower(value):
return value.lower()
13. config file
● move configuration to a file
app.config.from_pyfile( 'settings.py' )
● settings
DEBUG = True
...
14. flash messages
● use session to display messages in the next view
flask.flash("I have a message for you" )
● display messages in template
{% for message in get_flashed_messages() %}
<p class="msg"> ...
{% endfor %}
● put it in header.html then include it before content block in the layout
template
{% include 'other_template.html' %}
15. login
● view + template the same as new() - new.html
● handle the submitted username
if flask.request.method == 'POST':
username = flask.request.form['username' ]
...
● print username or flash it
{% extends 'layout.html' %}
{% block content %}
<form method="post">
<input name="username" >
<button type="submit"
>login</button>
</form>
{% endblock %}
16. session
● store something in session
flask.session['username' ] = username
● fetch and expose in templates
@app.before_request
def get_user():
flask.g.username = flask.session.get('username' )
● use in header
{% if g.username %}
logged in as {{ g.username }}
{% else %}
<a href="{{ url_for('login') }}" >login</a>
{% endif %}
17. logout
● clean the session in style
flask.session.pop('variable' , '')
● you
○ write a view logout()
○ route /logout to it
○ delete username from session
○ flash the message "bye bye"
○ redirect to home page
○ link to it in header
18. login required decorator
● redirect to login if not authenticated
def login_required(func):
@wraps(func)
def wrapper(*args, **kwargs):
if flask.g.username is None:
return flask.redirect('login')
return func(*args, **kwargs)
return wrapper
● use
@app.route('/private')
@login_required
def private_view():
...
● you: decorate new()
19. person model
● db model with id (Integer, primary_key) and username
(String)
● message author
class Message(db.Model):
...
person_id = db.Column(db.Integer, db .ForeignKey( 'person.id' ))
person = db.relationship( 'Person',
backref=db.backref('messages' , lazy='dynamic'))
● get or create Person
@classmethod
def get_or_create(cls, username):
person = cls.query.filter_by(username =username).first()
if person is None:
person = cls(username =username)
...
20. message and person
● when adding a message to db
text = flask.request.form['message']
person = Person.get_or_create(flask .g.username)
message = Message(text =text, time =datetime.utcnow(), person =person)
● when displaying in template
<p>
<strong>{{ message.person.username }}: </strong>
{{ message.text }}
</p>
21. person and messages
● add view for a person's feed
● route it to /<username>
@app.route( '/<username>' )
● get person or raise http 404
person = Person.query.filter_by(username =username).first_or_404()
● display messages in template
flask.render_template( 'messages.html' , messages =person.messages)
● show link to person's feed
...
{% set username = message.person.username %}
{% set url = url_for('person_feed', username=username) %}
<strong><a href="{{ url }}" >{{ username }} </a>:</strong>
...
22. static assets
● create a folder static/
● add style.css and some ninja CSS
● link to it in layout.html
<link rel="stylesheet" href="{{ url_for('static', filename='style.css')
}}">
/* style.css */
● wrap {% block content %} in <div class="container"> </div>
* { font-family: Ubuntu, arial }
body { background-color: #efefef }
.container {
width: 800px; margin: 0 auto;
background-color: #fff; }
p.msg {
background-color: #99ff99;
border-radius: 20px;
border: 1px solid green;
color: green: }
a { text-decoration: none }
23. wrapping up
we learned about: file structure:
● web application
mini.py
● url routing settings.py
static/
● templates
style.css
● sql templates/
header.html
● sessions
layout.html
messages.html
new.html
next:
● deployment options
● security, social extensions
24. see more
● full source code
https://github.com/mgax/minitwitter
● flask documentation
http://flask.pocoo.org/docs/