Flask intro - ROSEdu web workshops


Published on

The slides we used for a hands on workshop on Flask - micro web framework at http://events.rosedu.org/web-workshops

Published in: Technology
1 Like
  • Pentru aplicații mai mari, e ok să folosești __init__.py pentru inițializarea Flask, chiar recomandă asta: http://flask.pocoo.org/docs/patterns/packages/

    Vezi doar ca importurile celorlalte module (gen cel de view-uri) să fie la finalul __init__, ca să eviți importuri circulare.
    Are you sure you want to  Yes  No
    Your message goes here
  • am o întrebare, sper că e ok... unde ar trebui să inițializez Flask-ul, momentan o fac într-un __init__.py într-un modul și tot acolo adresez și cererile, știu că nu ar trebui să abuzez de 'init' se poate pune în altă parte?
    Are you sure you want to  Yes  No
    Your message goes here
No Downloads
Total views
On SlideShare
From Embeds
Number of Embeds
Embeds 0
No embeds

No notes for slide

Flask intro - ROSEdu web workshops

  1. 1. Flask intro rosedu web workshops27/03/2013 alex@grep.ro alex@eftimie.ro
  2. 2. prerequisites what well 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. 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)
  4. 4. virtualenv, pip# install system-wideapt-get install python-virtualenv# create newvirtualenv env# activatesource env/bin/activate# install flaskpip install flask# pip freezepip freeze > requirements.txt
  5. 5. basic flask app#!/usr/bin/env python (env)student@intel:~$ python mini. pyimport flask * Running on 5000/app = flask.Flask(__name__) - - [27/Mar/2013 01:13:app.config[DEBUG] = True 28] "GET / HTTP/1.1" 200 -@app.route( /)def home(): return "Hello World!"if __name__ == __main__ : app.run()
  6. 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. 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. 8. db; message model ● in a terminal:pip install SQLAlchemy Flask-SQLAlchemy● in mini.pyfrom flask.ext.sqlalchemy import SQLAlchemy...app.config[SQLALCHEMY_DATABASE_URI ] = sqlite:////tmp/test.dbdb = 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. 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. 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. 11. template filtersUsage: You:{{ variable |filter }} ● display message time in local timeCustom:@app.template_filter()def tolower(value): return value.lower()
  12. 12. common layout templatelayout.html <!doctype html> <html> ... {% block content %} {% endblock %} </html>messages.html {% extends layout.html %} {% block content %} goodies... {% endblock %}
  13. 13. config file● move configuration to a file app.config.from_pyfile( settings.py )● settings DEBUG = True ...
  14. 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. 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. 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. 17. logout● clean the session in styleflask.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. 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. 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. 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. 21. person and messages● add view for a persons feed● route it to /<username>@app.route( /<username> )● get person or raise http 404person = Person.query.filter_by(username =username).first_or_404()● display messages in templateflask.render_template( messages.html , messages =person.messages)● show link to persons feed ... {% set username = message.person.username %} {% set url = url_for(person_feed, username=username) %} <strong><a href="{{ url }}" >{{ username }} </a>:</strong> ...
  22. 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. 23. wrapping upwe 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.htmlnext:● deployment options● security, social extensions
  24. 24. see more● full source code https://github.com/mgax/minitwitter● flask documentation http://flask.pocoo.org/docs/