Modern Web Application Framework Python, SQL Alchemy, Jinja2 & Flask Devert Alexandre December 29, 2012 Slide 1/62
Table of Contents 1 Model-View-Controller 2 Flask 3 First steps 4 Routing 5 Templates Basic template rendering Using ressources Template inheritance Template macros Template language 6 Requests Devert Alexandre Modern Web Application Framework Slide 2/62
Model-View-Controller Most of the modern web development frameworks follow the Model-View-Controller model (MVC model) The model : representation of data. Usually, have a strong relation with the database The views : what is shown to the user. Can be any kind of user interface, usually HTML pages with Javascript. The controls : what operation are done on the data. It s a rather convenient way to design software projects involving user interfaces presenting and manipulating data. Devert Alexandre Modern Web Application Framework Slide 3/62
Model-View-Controller Application Controller manipulates Model updates View uses shows User Devert Alexandre Modern Web Application Framework Slide 4/62
Model-View-Controller Example for Model-View-Controller : an online management game The rule of the game, updating the state of each player the model The HTML pages, showing the various screen of the game the views The methods called when a user click on the screen the controllers Devert Alexandre Modern Web Application Framework Slide 5/62
Model-View-Controller Example for Model-View-Controller : an online shop The list of products, the payment rules, delivery orders the model The HTML pages, showing the various screen of the shop the views The methods for payment, order, shopping cart the controllers Devert Alexandre Modern Web Application Framework Slide 6/62
Model-View-Controller Model-View-Controller also helps to organize the work Some work on the views graphic designers, HTML, javascript Some work on the model database, software architecture Some work on the controls rather low-level and/or specialized code Some work on writing unit tests for at least the model and the views Devert Alexandre Modern Web Application Framework Slide 7/62
Table of Contents 1 Model-View-Controller 2 Flask 3 First steps 4 Routing 5 Templates Basic template rendering Using ressources Template inheritance Template macros Template language 6 Requests Devert Alexandre Modern Web Application Framework Slide 8/62
Web application with script language Why using a scripting language for a web application? More adapted language to paste together various components (database, rendering, routing,... ) Make its easier to release early & often Easier to maintain & modify Speed far enough for many use case Devert Alexandre Modern Web Application Framework Slide 9/62
Web application with script language Why not PHP, or PHP framework? Designed to make simple web pages, not large web applications Awfully designed programming language very inconsistent libraries very little help for debugging many security issues many better alternatives Detailed explanation here http://me.veekun.com/blog/2012/04/09/php-a-fractal-ofbad-design Devert Alexandre Modern Web Application Framework Slide 10/62
Web application with script language Why not using Java/JSP/JBoss/Apache/Hibernate/Spring? Even simple changes requires lots of coding Big changes takes a lot of planning Edit/Compile/Run takes more ressource General speed of development much reduced Working without a big fat IDE is tedious But you can use those all this with a script-like language : Grails and Groovy Devert Alexandre Modern Web Application Framework Slide 11/62
Flask I am going to introduce the framework Flask It is small : quick to learn and master It is complete : you can use to do serious apps It is lean : a shell and a text editor are enough, no need for an IDE to be efficient with it It is very well documented The same ideas can be found in most web development frameworks. Devert Alexandre Modern Web Application Framework Slide 12/62
Flask Flask is a nice glue around existing tools Python programming language SQL Alchemy database Jinja2 HTML template system Werkzeug WSCGI handling (CGI, but better) Devert Alexandre Modern Web Application Framework Slide 13/62
Table of Contents 1 Model-View-Controller 2 Flask 3 First steps 4 Routing 5 Templates Basic template rendering Using ressources Template inheritance Template macros Template language 6 Requests Devert Alexandre Modern Web Application Framework Slide 14/62
Hello, world! A minimal Flask application from f l a s k i m p o r t F l a s k app = F l a s k ( n a m e ) @app. r o u t e ( / ) d e f h e l l o ( ) : r e t u r n H e l l o World! i f n a m e == m a i n : app. run ( ) Run this, and open your web browser at http://127.0.0.1:5000 Devert Alexandre Modern Web Application Framework Slide 15/62
Hello, world! You will see this Devert Alexandre Modern Web Application Framework Slide 16/62
Hello, world! This creates an application instance and run it from f l a s k i m p o r t F l a s k app = F l a s k ( n a m e ) i f n a m e == m a i n : app. run ( ) Devert Alexandre Modern Web Application Framework Slide 17/62
Hello, world! This adds the hello method to the application instance @app. r o u t e ( / ) d e f h e l l o ( ) : r e t u r n H e l l o World! hello() will be called every time the address / is requested hello() returns the text data for the web browser Devert Alexandre Modern Web Application Framework Slide 18/62
Debugging Triggering the debug mode is easy from f l a s k i m p o r t F l a s k app = F l a s k ( n a m e ) @app. r o u t e ( / ) d e f h e l l o ( ) : r e t u r n H e l l o World! i f n a m e == m a i n : app. run ( debug = True ) In debug mode, you can edit the code while the server runs : it will restart! Devert Alexandre Modern Web Application Framework Slide 19/62
Debugging The debug mode will also helps a lot to point where the problem is Devert Alexandre Modern Web Application Framework Slide 20/62
Table of Contents 1 Model-View-Controller 2 Flask 3 First steps 4 Routing 5 Templates Basic template rendering Using ressources Template inheritance Template macros Template language 6 Requests Devert Alexandre Modern Web Application Framework Slide 21/62
Function / URL mapping When an URL is requested, Flask will look for its corresponding function. from f l a s k i m p o r t F l a s k app = F l a s k ( n a m e ) @app. r o u t e ( / ) d e f i n d e x ( ) : r e t u r n I n d e x Page @app. r o u t e ( / welcome ) d e f h e l l o ( ) : r e t u r n He ll o World i f n a m e == m a i n : app. run ( ) One function return text data. It can be HTM, XML, JSON, etc. Devert Alexandre Modern Web Application Framework Slide 22/62
Function / URL mapping You can defines URL with parameters @app. route ( /show name/<name> ) def print name ( name ) : r e t u r n H e l l o, %s! % name It gives a nice way, intuitive way to define ressources on a website. Devert Alexandre Modern Web Application Framework Slide 23/62
Function / URL mapping You can make URL parameters optional @app. r o u t e ( / h e l l o / ) @app. r o u t e ( / h e l l o /<name> ) d e f h e l l o ( name = None ) : i f name i s None : r e t u r n A h o r s e with no name e l s e : return A horse named %s % name Devert Alexandre Modern Web Application Framework Slide 24/62
Function / URL mapping You can enforce the type of a parameter @app. r o u t e ( /team/< i n t : team id> ) def show team ( team id ) : r e t u r n team #%d % team id Flask will check the type for you Devert Alexandre Modern Web Application Framework Slide 25/62
Function / URL mapping You can translate function names to URL with url for() @app. r o u t e ( / ) d e f welcome ( ) : r e t u r n H e l l o World! @app. r o u t e ( / t e s t ) d e f t e s t ( ) : name = welcome r e t u r n u r l f o r %s = %s % ( name, u r l f o r ( name ) ) Especially convenient when you might have to change the URL naming scheme Devert Alexandre Modern Web Application Framework Slide 26/62
Function / URL mapping url for() also works for URL with parameters @app. route ( /show name/<name> ) def print name ( name ) : r e t u r n H e l l o, %s! % name @app. r o u t e ( / t e s t ) d e f t e s t ( ) : func name, user name = print name, Alex r e t u r n u r l f o r %s = %s % ( func name, u r l f o r ( func name, name = user name ) ) Devert Alexandre Modern Web Application Framework Slide 27/62
Catching HTTP errors The HTTP protocol defines several status codes. status code meaning 400 Bad Request 401 Unauthorized 402 Payment Required 403 Forbidden 404 Not Found 500 Internal Server Error 501 Not Implemented 503 Service Unavailable Devert Alexandre Modern Web Application Framework Slide 28/62
Catching HTTP errors Using @errorhandler, you can catch such errors @app. e r r o r h a n d l e r ( 4 0 3 ) d e f p a g e f o r b i d d e n ( e r r o r ) : p r i n t Hey! You a r e not a l l o w e d to a c c e s s t h i s! @app. e r r o r h a n d l e r ( 4 0 4 ) d e f p a g e n o t f o u n d ( e r r o r ) : p r i n t Ho no! The r e s s o u r c e you want to a c c e s s does not e x i s t : ( Devert Alexandre Modern Web Application Framework Slide 29/62
Throwing HTTP errors It is also possible to throw HTTP errors with abort @app. r o u t e ( / s h o w a c c o u n t i n f o s ) def show account infos ( ) : i f not u s e r. l o g g e d i n : a b o r t ( 401) # Do t h i n g s... For instance, an error 401 to deny access to ressources Devert Alexandre Modern Web Application Framework Slide 30/62
Table of Contents 1 Model-View-Controller 2 Flask 3 First steps 4 Routing 5 Templates Basic template rendering Using ressources Template inheritance Template macros Template language 6 Requests Devert Alexandre Modern Web Application Framework Slide 31/62
The need for templates Generating HTML directly with code Easy to make very hard to read code Mix-up the control code with the view code Text template system is a convenient and common way to separade the view code from the remaining code Devert Alexandre Modern Web Application Framework Slide 32/62
The need for templates Flask uses Jinja2 as template system. There are many others template system Mako, for Python (if you ask me, it s better than Jinja2) JSP, for Java, THE standard for Java. Allow to mix Java & HTML. ASP, for Microsoft products. Allow to mix VBScript & HTML. XSLT is a template system based on XML. Plateform indepedent but not very convenient in practice. Maybe 10 different for every language you can think of Devert Alexandre Modern Web Application Framework Slide 33/62
Basic template rendering The function render template takes a path to an HTML file, and arbitrary parameters from f l a s k import Flask, render template app = F l a s k ( n a m e ) @app. r o u t e ( / h e l l o / ) @app. r o u t e ( / h e l l o /<name> ) d e f h e l l o ( name = None ) : r e t u r n r e n d e r t e m p l a t e ( h e l l o. html, name = name ) i f n a m e == m a i n : app. run ( ) What will be returned will the content of hello.html Devert Alexandre Modern Web Application Framework Slide 34/62
Basic template rendering The HTML file hello.html <! d o c t y p e html> <html> <head> < t i t l e>the w e b s i t e t h a t s a y s H e l l o to you</ t i t l e> </ head> <body> {% i f name %} <h1>h e l l o, {{ name }}!</h1> {% e l s e %} <h1>hello, thing with no name!</h1> {% e n d i f %} </ body> </ html> It s no ordinary HTML there are instruction mixed in! Devert Alexandre Modern Web Application Framework Slide 35/62
Basic template rendering The HTML file hello.html <! d o c t y p e html> <html> <head> < t i t l e>the w e b s i t e t h a t s a y s H e l l o to you</ t i t l e> </ head> <body> {% i f name %} <h1>h e l l o, {{ name }}!</h1> {% e l s e %} <h1>hello, thing with no name!</h1> {% e n d i f %} </ body> </ html> hello.html is processed to generate the HTML to send to a user. Here, we use the name variable, passed as a parameter of render template Devert Alexandre Modern Web Application Framework Slide 35/62
Basic template rendering The HTML file hello.html <! d o c t y p e html> <html> <head> < t i t l e>the w e b s i t e t h a t s a y s H e l l o to you</ t i t l e> </ head> <body> {% i f name %} <h1>h e l l o, {{ name }}!</h1> {% e l s e %} <h1>hello, thing with no name!</h1> {% e n d i f %} </ body> </ html> Variables values can be rendered to text with {{ }} Devert Alexandre Modern Web Application Framework Slide 35/62
Basic template rendering The HTML file hello.html <! d o c t y p e html> <html> <head> < t i t l e>the w e b s i t e t h a t s a y s H e l l o to you</ t i t l e> </ head> <body> {% i f name %} <h1>h e l l o, {{ name }}!</h1> {% e l s e %} <h1>hello, thing with no name!</h1> {% e n d i f %} </ body> </ html> Blocks of code are put between {% %} Devert Alexandre Modern Web Application Framework Slide 35/62
Basic template rendering Flask assumes that all your templates will be in a template directory, relative to your script t e m p l a t e s h e l l o. html t e s t. py Devert Alexandre Modern Web Application Framework Slide 36/62
Using ressources If you wish to use other file ressources, like pictures or CSS files, you can put them in directory named static t e m p l a t e s h e l l o. html s t a t i c s t y l e. c s s t e s t. py Those resource are not dynamic, not generated on the fly like the HTML code, hence the name static Devert Alexandre Modern Web Application Framework Slide 37/62
Using ressources Then, to use those ressources, you can again use url for <! d o c t y p e html> <html> <head> < t i t l e>the w e b s i t e t h a t s a y s H e l l o to you</ t i t l e> <l i n k r e l=s t y l e s h e e t t y p e=t e x t / c s s h r e f= {{ u r l f o r ( s t a t i c, f i l e n a m e = s t y l e. css ) }} > </ head> <body> {% i f name %} <h1>h e l l o, {{ name }}!</h1> {% e l s e %} <h1>hello, thing with no name!</h1> {% e n d i f %} </ body> </ html> Devert Alexandre Modern Web Application Framework Slide 38/62
Template inheritance On a typical website, different views follow a similar design Devert Alexandre Modern Web Application Framework Slide 39/62
Template inheritance On a typical website, different views follow a similar design Devert Alexandre Modern Web Application Framework Slide 39/62
Template inheritance On a typical website, different views follow a similar design Devert Alexandre Modern Web Application Framework Slide 39/62
Template inheritance On a typical website, different views follow a similar design Devert Alexandre Modern Web Application Framework Slide 39/62
Template inheritance Jinja2 provides a simple way to share a common template and specialize it : template inheritance {% e x t e n d s base. html %} {% b l o c k c o n t e n t %} {% i f name %} <h2>h e l l o, {{ name }}!</h2> {% e l s e %} <h2>hello, thing with no name!</h2> {% e n d i f %} {% e n d b l o c k %} hello.html extends base.html Devert Alexandre Modern Web Application Framework Slide 40/62
Template inheritance Jinja2 provides a simple way to share a common template and specialize it : template inheritance {% e x t e n d s base. html %} {% b l o c k c o n t e n t %} {% i f name %} <h2>goodbye, {{ name }}!</h2> {% e l s e %} <h2>goodbye, thing with no name!</h2> {% e n d i f %} {% e n d b l o c k %} goodbye.html extends base.html Devert Alexandre Modern Web Application Framework Slide 40/62
Template inheritance And base.html look like this <!DOCTYPE HTML PUBLIC //W3C//DTD HTML 4.01//EN > <html l a n g= en > <head> < t i t l e>s a l u t e. com, t h e w e b s i t e t h a t s a l u t e s you</ t i t l e> <l i n k r e l=s t y l e s h e e t t y p e=t e x t / c s s h r e f= {{ u r l f o r ( s t a t i c, f i l e n a m e = s t y l e. c s s </ head> <body> <div id= container > <div id= header > <h1>salute. com</h1> <p>the w e b s i t e t h a t s a l u t e s you</p> </ d i v> <div id= content > {% b l o c k c o n t e n t %}{% e n d b l o c k %} </ d i v> </ d i v> <d i v i d= f o o t e r > <h2>salute. com</h2> <p>s i t e design & ; copyright © ; Alexandre Devert</p> </ d i v> </ body> </ html> Devert Alexandre Modern Web Application Framework Slide 41/62
Template inheritance On the Python side, hello.html and goodbye.html are just normal HTML pages, nothing special to do @app. r o u t e ( / h e l l o / ) @app. r o u t e ( / h e l l o /<name> ) d e f h e l l o ( name = None ) : r e t u r n r e n d e r t e m p l a t e ( h e l l o. html, name = name ) @app. r o u t e ( / goodbye / ) @app. r o u t e ( / goodbye/<name> ) def goodbye ( name = None ) : r e t u r n r e n d e r t e m p l a t e ( goodbye. html, name = name ) Devert Alexandre Modern Web Application Framework Slide 42/62
Template inheritance In this exemple, extending base.html provides A common title Includes common ressources (css, javascript, etc.) A common header A common footer The specialized part goes in the content block. Coherent look, code reusage, and clean separation! Devert Alexandre Modern Web Application Framework Slide 43/62
Template macros On a website, the same user interface elements are often re-used Devert Alexandre Modern Web Application Framework Slide 44/62
Template macros On a website, the same user interface elements are often re-used Devert Alexandre Modern Web Application Framework Slide 44/62
Template macros We can define reusable HTML bits of codes. {% macro r e n d e r p a n e l ( t i t l e, s t y l e= l e f t ) %} <d i v c l a s s= p a n e l > <h1 c l a s s= {{ s t y l e }} >{{ t i t l e }}</h1> <d i v c l a s s= panel c o n t e n t > <d i v c l a s s= {{ s t y l e }} > {{ c a l l e r ( ) }} </ d i v> </ d i v> </ d i v> {% endmacro %} This define a box, containing whatever caller() will put in it, and with a title. We put this in ui.html Devert Alexandre Modern Web Application Framework Slide 45/62
Template macros Now, we can create lots of boxes. {% e x t e n d s base. html %} {% i m p o r t u i. html as u i %} {% b l o c k c o n t e n t %} <div c l a s s= three columns layout > <d i v c l a s s= l e f t column > {% c a l l u i. r e n d e r p a n e l ( Lorem ipsum, l e f t ) %}... b l a b l a... {% e n d c a l l %} {% c a l l u i. r e n d e r p a n e l ( Lorem ipsum, l e f t ) %}... b l a b l a... {% e n d c a l l %} </ d i v> <d i v c l a s s= r i g h t column > {% c a l l u i. r e n d e r p a n e l ( H i s t o r y, l e f t ) %}... b l a b l a... {% e n d c a l l %} {% c a l l u i. r e n d e r p a n e l ( Now i s t h e time f o r a l l good men, l e f t ) %}... b l a b l a... {% e n d c a l l %} </ d i v> </ d i v> {% e n d b l o c k %} No need to copy paste the same HTML code around! Devert Alexandre Modern Web Application Framework Slide 46/62
Template macros To use a macro, first import the file that contains that macro {% i m p o r t u i. html as u i %} Then you can call the macro {% c a l l u i. r e n d e r p a n e l ( My T i t l e Here, l e f t ) %}... b l a b l a... {% e n d c a l l %} What is between call and endcall could be any valid HTML code. It will be placed in place of caller in the macro definition. Devert Alexandre Modern Web Application Framework Slide 47/62
Template language Jinja templates use their own language, more or less Python-like. It tries to imitate Python But it is not Python Why not having full power of Python in a template? Devert Alexandre Modern Web Application Framework Slide 48/62
Template language Jinja provides a limited language because It s a view. No business code here. Just HTML generation. It s a page that might be served for many different users. Should be fast. Devert Alexandre Modern Web Application Framework Slide 49/62
Template language The if block works like Python {% i f show advertisement %} <h1>buy Drunk Panda, the b e s t beer i n Suzhou!</h1> {% e n d i f %} Devert Alexandre Modern Web Application Framework Slide 50/62
Template language An optional else block works can be used {% i f show advertisement %} <h1>buy Drunk Panda, the b e s t beer i n Suzhou!</h1> {% e l s e %} Do not buy a n y t h i n g {% e n d i f %} Devert Alexandre Modern Web Application Framework Slide 51/62
Template language An even elif blocks are available {% i f show beer advertisement %} <h1>buy Drunk Panda, the b e s t beer i n Suzhou!</h1> {% e l i f s h o w p i z z a a d v e r t i s e m e n t %} <h1>buy Pizza Hut, the worst p i z z a s ever!</h1> {% e l s e %} Do not buy a n y t h i n g {% e n d i f %} Devert Alexandre Modern Web Application Framework Slide 52/62
Template language The Jinja for loop works like the Python one {% f o r item i n n a v i g a t i o n %} < l i> <a h r e f= {{ item. h r e f }} >{{ item. c a p t i o n }}</a> </ l i> {% e n d f o r %} Note that navigation is a sequence, passed to the template item is one item of the sequence loop code is between {% for %} and {% endfor %} Devert Alexandre Modern Web Application Framework Slide 53/62
Template language Jinja provides a loop object that can be called inside a for loop {% f o r item i n n a v i g a t i o n %} < l i> <a h r e f= {{ item. h r e f }} >{{ l o o p. i n d e x }} {{ item. c a p t i o n }}</a> </ l i> {% e n d f o r %} Devert Alexandre Modern Web Application Framework Slide 54/62
Template language This loop object provides some useful informations about the current item of the loop loop variable loop.index loop.index0 loop.revindex loop.revindex0 loop.last loop.first meaning Current index (1-indexed) Current index (0-indexed) Current index, reversed order (1-indexed) Current index, reversed order (0-indexed) True if last item True if first item Devert Alexandre Modern Web Application Framework Slide 55/62
Template language You can filter the for loop, as in Python {% f o r u s e r i n u s e r l i s t i f not u s e r. i s h i d d e n %} < l i> {{ u s e r. name }} </ l i> {% e n d f o r %} Devert Alexandre Modern Web Application Framework Slide 56/62
Template language If the sequence you iterate turns out to be empty, you can catch this case with an else block {% f o r u s e r i n u s e r l i s t i f not u s e r. i s h i d d e n %} < l i> {{ u s e r. name }} </ l i> {% e l s e %} No u s e r s found! {% e n d f o r %} Devert Alexandre Modern Web Application Framework Slide 57/62
Table of Contents 1 Model-View-Controller 2 Flask 3 First steps 4 Routing 5 Templates Basic template rendering Using ressources Template inheritance Template macros Template language 6 Requests Devert Alexandre Modern Web Application Framework Slide 58/62
Requests We can send data (HTML, JSON, XML, any kind of text), but we also need to receive data passwords checkboxes values... Devert Alexandre Modern Web Application Framework Slide 59/62
Requests The HTTP protocol defines different kind of requests GET request to send data POST request to accept data So far, we only handled GET requests : sending HTML data. Devert Alexandre Modern Web Application Framework Slide 60/62
Requests We can also handle POST requests, like this from f l a s k i m p o r t r e q u e s t @app. r o u t e ( / l o g i n, methods = [ GET, POST ] ) d e f l o g i n ( ) : # GET r e q u e s t i f request. method == GET : r e t u r n r e n d e r t e m p l a t e ( l o g i n. html ) # POST REQUEST e l s e : e m a i l = r e q u e s t. form [ e m a i l ] password = r e q u e s t. form [ password ] # Check e m a i l & password # TODO r e t u r n r e n d e r t e m p l a t e ( welcome. html ) Devert Alexandre Modern Web Application Framework Slide 61/62
Requests The request object hold the information sent to the server <form name= l o g i n method= p o s t a c t i o n= {{ u r l f o r ( l o g i n ) }} > <l a b e l>email</ l a b e l> <input type= text name= email maxlength= 254 /> <l a b e l>password</ l a b e l> <input type= password name= password /> <button </ form> type= submit >Enter</ button> Devert Alexandre Modern Web Application Framework Slide 62/62