Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Python Web Development with Flask

Python Web Development with Flask

These are the slides I used for my O'Reilly webcast on 5/13/2014.

Miguel Grinberg

May 13, 2014
Tweet

More Decks by Miguel Grinberg

Other Decks in Programming

Transcript

  1. Who am I? My blog http://blog.miguelgrinberg.com is powered by Flask.

    I wrote the Flask Mega-Tutorial 18-part series. I wrote several articles on API development with Flask. My most popular Flask extensions: Flask-SocketIO (WebSocket communication) Flask-Migrate (Database migrations with Alembic) Flask-HTTPAuth (RESTful authentication) Flask-PageDown (Live Markdown editor) Flask-Moment (Rendering of dates and times) I did two PyCon 2014 talks on Flask (watch them on pyvideo.org). I wrote the O'Reilly book "Flask Web Development".
  2. What is Flask? The official version: Server-side Web micro-framework for

    Python Very small: ~2100 LOC Well documented Supports Python 2.6, 2.7 and 3.3+ What Flask does, in practice: It makes it super easy to work with HTTP requests and responses. It stays completely out of the way for everything else. Topics such as databases, user authentication, etc. are not Flask's concern, you have total freedom to choose the components of your application.
  3. Installation The most convenient way to install Flask is in

    a virtual environment. If you are using bash or similar: $ v i r t u a l e n v e n v $ s o u r c e v e n v / b i n / a c t i v a t e ( v e n v ) $ p i p i n s t a l l f l a s k If you are using the Windows command prompt: > v i r t u a l e n v e n v > v e n v \ S c r i p t s \ a c t i v a t e ( v e n v ) > p i p i n s t a l l f l a s k If you use Python 3.4 you can replace v i r t u a l e n v with p y v e n v .
  4. Example Code GitHub project: https://github.com/miguelgrinberg/flask-webcast Requirements: Git command line client

    Python interpreter, one of the two options: Version 2.7 or 3.3, with v i r t u a l e n v installed Version 3.4 (no need to install v i r t u a l e n v !) Detailed installation instructions are in the project's R E A D M E file.
  5. Anatomy of a Flask Application Step 1: Create an application

    instance. f r o m f l a s k i m p o r t F l a s k a p p = F l a s k ( _ _ n a m e _ _ ) @ a p p . r o u t e ( ' / ' ) d e f i n d e x ( ) : r e t u r n ' < h 1 > H e l l o , W o r l d ! < / h 1 > ' @ a p p . r o u t e ( ' / u s e r / < n a m e > ' ) d e f u s e r ( n a m e ) : r e t u r n ' < h 1 > H e l l o , { 0 } ! < / h 1 > ' . f o r m a t ( n a m e ) i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( d e b u g = T r u e )
  6. Anatomy of a Flask Application Step 2: Define routes. f

    r o m f l a s k i m p o r t F l a s k a p p = F l a s k ( _ _ n a m e _ _ ) @ a p p . r o u t e ( ' / ' ) d e f i n d e x ( ) : r e t u r n ' < h 1 > H e l l o , W o r l d ! < / h 1 > ' @ a p p . r o u t e ( ' / u s e r / < n a m e > ' ) d e f u s e r ( n a m e ) : r e t u r n ' < h 1 > H e l l o , { 0 } ! < / h 1 > ' . f o r m a t ( n a m e ) i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( d e b u g = T r u e )
  7. Anatomy of a Flask Application Step 3: Start the development

    web server. f r o m f l a s k i m p o r t F l a s k a p p = F l a s k ( _ _ n a m e _ _ ) @ a p p . r o u t e ( ' / ' ) d e f i n d e x ( ) : r e t u r n ' < h 1 > H e l l o , W o r l d ! < / h 1 > ' @ a p p . r o u t e ( ' / u s e r / < n a m e > ' ) d e f u s e r ( n a m e ) : r e t u r n ' < h 1 > H e l l o , { 0 } ! < / h 1 > ' . f o r m a t ( n a m e ) i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( d e b u g = T r u e )
  8. Running a Flask Application To run, simply execute the script:

    ( v e n v ) $ p y t h o n h e l l o . p y * R u n n i n g o n h t t p : / / 1 2 7 . 0 . 0 . 1 : 5 0 0 0 / * R e s t a r t i n g w i t h r e l o a d e r You can access the application from your browser at http://localhost:5000.
  9. Templates Templates help separate the presentation logic from the rest

    of the application. f r o m f l a s k i m p o r t F l a s k , r e n d e r _ t e m p l a t e a p p = F l a s k ( _ _ n a m e _ _ ) @ a p p . r o u t e ( ' / ' ) d e f i n d e x ( ) : r e t u r n r e n d e r _ t e m p l a t e ( ' i n d e x . h t m l ' ) @ a p p . r o u t e ( ' / u s e r / < n a m e > ' ) d e f u s e r ( n a m e ) : r e t u r n r e n d e r _ t e m p l a t e ( ' u s e r . h t m l ' , n a m e = n a m e ) i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( d e b u g = T r u e )
  10. Templates Templates are written as regular text files in a

    templates folder. templates/index.html: < h 1 > H e l l o , W o r l d ! < / h 1 > templates/user.html: < h 1 > H e l l o , { { n a m e } } ! < / h 1 >
  11. Templates Other important Jinja2 features: Control structures Template inheritance Macros

    Sub-templates Related extensions: Flask-Bootstrap is an excellent extension for Flask that integrates the Twitter Bootstrap framework into your application to make it look awesome.
  12. Web Forms Web forms are defined in templates using standard

    HTML syntax. templates/index.html: < ! D O C T Y P E H T M L > < h t m l > < h e a d > < t i t l e > H e l l o E x a m p l e < / t i t l e > < / h e a d > < b o d y > < f o r m m e t h o d = " P O S T " a c t i o n = " " > W h a t i s y o u r n a m e ? < i n p u t t y p e = " t e x t " n a m e = " n a m e " > < i n p u t t y p e = " s u b m i t " n a m e = " s u b m i t " v a l u e = " S u b m i t " > < / f o r m > { % i f n a m e % } < h 1 > H e l l o , { { n a m e } } ! < / h 1 > { % e n d i f % } < / b o d y > < / h t m l >
  13. Web Forms Conditionals can be used in templates similarly to

    how they are used in code. templates/index.html: < ! D O C T Y P E H T M L > < h t m l > < h e a d > < t i t l e > H e l l o E x a m p l e < / t i t l e > < / h e a d > < b o d y > < f o r m m e t h o d = " P O S T " a c t i o n = " " > W h a t i s y o u r n a m e ? < i n p u t t y p e = " t e x t " n a m e = " n a m e " > < i n p u t t y p e = " s u b m i t " n a m e = " s u b m i t " v a l u e = " S u b m i t " > < / f o r m > { % i f n a m e % } < h 1 > H e l l o , { { n a m e } } ! < / h 1 > { % e n d i f % } < / b o d y > < / h t m l >
  14. Web Forms The route function needs to accept G E

    T and P O S T requests. f r o m f l a s k i m p o r t F l a s k , r e n d e r _ t e m p l a t e , r e q u e s t a p p = F l a s k ( _ _ n a m e _ _ ) @ a p p . r o u t e ( ' / ' , m e t h o d s = [ ' G E T ' , ' P O S T ' ] ) d e f i n d e x ( ) : n a m e = N o n e i f r e q u e s t . m e t h o d = = ' P O S T ' a n d ' n a m e ' i n r e q u e s t . f o r m : n a m e = r e q u e s t . f o r m [ ' n a m e ' ] r e t u r n r e n d e r _ t e m p l a t e ( ' i n d e x . h t m l ' , n a m e = n a m e ) i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( d e b u g = T r u e )
  15. Web Forms Flask's r e q u e s t

    object provides access to the form data. f r o m f l a s k i m p o r t F l a s k , r e n d e r _ t e m p l a t e , r e q u e s t a p p = F l a s k ( _ _ n a m e _ _ ) @ a p p . r o u t e ( ' / ' , m e t h o d s = [ ' G E T ' , ' P O S T ' ] ) d e f i n d e x ( ) : n a m e = N o n e i f r e q u e s t . m e t h o d = = ' P O S T ' a n d ' n a m e ' i n r e q u e s t . f o r m : n a m e = r e q u e s t . f o r m [ ' n a m e ' ] r e t u r n r e n d e r _ t e m p l a t e ( ' i n d e x . h t m l ' , n a m e = n a m e ) i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( d e b u g = T r u e ) r e q u e s t . m e t h o d can be used to differentiate between G E T and P O S T requests. r e q u e s t . f o r m is a Python dictionary with the form data entered by the user.
  16. Web Forms Related extensions: Flask-WTF is a useful extension that

    provides an object-oriented approach to creating and validating forms. Flask-Bootstrap contains a Jinja2 macro that can render a Flask-WTF form using Bootstrap styles.
  17. Database For this example we are going to use a

    free MongoDB database from MongoHQ. Go to http://www.mongohq.com/ and sign up for a free 512MB sandbox MongoDB database. Name your database n a m e s . Create a username and password. Obtain the URI for your database, which will be something like mongodb://<user>:<password>@oceanic.mongohq.com:10008/names. To access this database from Flask we are going to use an extension called Flask- PyMongo. Extensions are installed into the virtual environment with pip: ( v e n v ) $ p i p i n s t a l l f l a s k - p y m o n g o
  18. Database Step 1: Configure the extension i m p o

    r t o s f r o m f l a s k i m p o r t F l a s k , r e n d e r _ t e m p l a t e , r e q u e s t f r o m f l a s k . e x t . p y m o n g o i m p o r t P y M o n g o a p p = F l a s k ( _ _ n a m e _ _ ) a p p . c o n f i g [ ' M O N G O _ U R I ' ] = o s . e n v i r o n [ ' M O N G O _ U R I ' ] m o n g o = P y M o n g o ( a p p ) @ a p p . r o u t e ( ' / ' , m e t h o d s = [ ' G E T ' , ' P O S T ' ] ) d e f i n d e x ( ) : n a m e = N o n e n e w = F a l s e i f r e q u e s t . m e t h o d = = ' P O S T ' a n d ' n a m e ' i n r e q u e s t . f o r m : n a m e = r e q u e s t . f o r m [ ' n a m e ' ] i f m o n g o . d b . n a m e s . f i n d _ o n e ( { ' n a m e ' : n a m e } ) i s N o n e : m o n g o . d b . n a m e s . i n s e r t ( { ' n a m e ' : n a m e } ) n e w = T r u e r e t u r n r e n d e r _ t e m p l a t e ( ' i n d e x . h t m l ' , n a m e = n a m e , n e w = n e w ) i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( d e b u g = T r u e )
  19. Database Step 2: Add database logic to route i m

    p o r t o s f r o m f l a s k i m p o r t F l a s k , r e n d e r _ t e m p l a t e , r e q u e s t f r o m f l a s k . e x t . p y m o n g o i m p o r t P y M o n g o a p p = F l a s k ( _ _ n a m e _ _ ) a p p . c o n f i g [ ' M O N G O _ U R I ' ] = o s . e n v i r o n [ ' M O N G O _ U R I ' ] m o n g o = P y M o n g o ( a p p ) @ a p p . r o u t e ( ' / ' , m e t h o d s = [ ' G E T ' , ' P O S T ' ] ) d e f i n d e x ( ) : n a m e = N o n e n e w = F a l s e i f r e q u e s t . m e t h o d = = ' P O S T ' a n d ' n a m e ' i n r e q u e s t . f o r m : n a m e = r e q u e s t . f o r m [ ' n a m e ' ] i f m o n g o . d b . n a m e s . f i n d _ o n e ( { ' n a m e ' : n a m e } ) i s N o n e : m o n g o . d b . n a m e s . i n s e r t ( { ' n a m e ' : n a m e } ) n e w = T r u e r e t u r n r e n d e r _ t e m p l a t e ( ' i n d e x . h t m l ' , n a m e = n a m e , n e w = n e w ) i f _ _ n a m e _ _ = = ' _ _ m a i n _ _ ' : a p p . r u n ( d e b u g = T r u e )
  20. Database Step 3: Customize the greeting in the template <

    ! D O C T Y P E H T M L > < h t m l > < h e a d > < t i t l e > F l a s k E x a m p l e < / t i t l e > < / h e a d > < b o d y > < f o r m m e t h o d = " P O S T " a c t i o n = " " > W h a t i s y o u r n a m e ? < i n p u t t y p e = " t e x t " n a m e = " n a m e " > < i n p u t t y p e = " s u b m i t " n a m e = " s u b m i t " v a l u e = " S u b m i t " > < / f o r m > { % i f n a m e % } < h 1 > H e l l o , { { n a m e } } ! < / h 1 > { % i f n e w % } < p > N i c e t o m e e t y o u ! < / p > { % e l s e % } < p > G r e a t t o s e e y o u a g a i n ! < / p > { % e n d i f % } { % e n d i f % } < / b o d y > < / h t m l >
  21. Project Structure Coding an entire application in a single script

    is useful for quick & dirty tests, but not for intermediate or large applications. Flask does not have any rules for structuring an application. The following example is just one possible way to structure the application. You are encouraged to change and customize it to your liking!
  22. Project Structure h e l l o _ a p

    p \ R o o t f o l d e r a p p \ A p p l i c a t i o n p a c k a g e t e m p l a t e s \ T e m p l a t e f o l d e r h e l l o \ B l u e p r i n t s p e c i f i c t e m p l a t e s s t a t i c \ S t a t i c f i l e s ( . c s s , . j s , e t c . ) h e l l o \ B l u e p r i n t _ _ i n i t _ _ . p y B l u e p r i n t c o n s t r u c t o r r o u t e s . p y B l u e p r i n t r o u t e s _ _ i n i t _ _ . p y A p p l i c a t i o n f a c t o r y t e s t s \ U n i t t e s t s p a c k a g e c o n f i g _ d e v e l o p m e n t . p y D e v e l o p m e n t c o n f i g u r a t i o n c o n f i g _ t e s t i n g . p y U n i t t e s t i n g c o n f i g u r a t i o n c o n f i g _ p r o d u c t i o n . p y P r o d u c t i o n c o n f i g u r a t i o n m a n a g e . p y L a u n c h s c r i p t
  23. Project Structure | Configuration h e l l o _

    a p p \ R o o t f o l d e r a p p \ A p p l i c a t i o n p a c k a g e t e m p l a t e s \ T e m p l a t e f o l d e r h e l l o \ B l u e p r i n t s p e c i f i c t e m p l a t e s s t a t i c \ S t a t i c f i l e s ( . c s s , . j s , e t c . ) h e l l o \ B l u e p r i n t _ _ i n i t _ _ . p y B l u e p r i n t c o n s t r u c t o r r o u t e s . p y B l u e p r i n t r o u t e s _ _ i n i t _ _ . p y A p p l i c a t i o n f a c t o r y t e s t s \ U n i t t e s t s p a c k a g e c o n f i g _ d e v e l o p m e n t . p y D e v e l o p m e n t c o n f i g u r a t i o n c o n f i g _ t e s t i n g . p y U n i t t e s t i n g c o n f i g u r a t i o n c o n f i g _ p r o d u c t i o n . p y P r o d u c t i o n c o n f i g u r a t i o n m a n a g e . p y L a u n c h s c r i p t Several configuration files are written for different usage cases, at least for development, testing and production use.
  24. Project Structure | Application Package h e l l o

    _ a p p \ R o o t f o l d e r a p p \ A p p l i c a t i o n p a c k a g e t e m p l a t e s \ T e m p l a t e f o l d e r h e l l o \ B l u e p r i n t s p e c i f i c t e m p l a t e s s t a t i c \ S t a t i c f i l e s ( . c s s , . j s , e t c . ) h e l l o \ B l u e p r i n t _ _ i n i t _ _ . p y B l u e p r i n t c o n s t r u c t o r r o u t e s . p y B l u e p r i n t r o u t e s _ _ i n i t _ _ . p y A p p l i c a t i o n f a c t o r y t e s t s \ U n i t t e s t s p a c k a g e c o n f i g _ d e v e l o p m e n t . p y D e v e l o p m e n t c o n f i g u r a t i o n c o n f i g _ t e s t i n g . p y U n i t t e s t i n g c o n f i g u r a t i o n c o n f i g _ p r o d u c t i o n . p y P r o d u c t i o n c o n f i g u r a t i o n m a n a g e . p y L a u n c h s c r i p t The application is moved down to the a p p package, with sub-folders for templates and static files.
  25. Project Structure | Application Package h e l l o

    _ a p p \ R o o t f o l d e r a p p \ A p p l i c a t i o n p a c k a g e t e m p l a t e s \ T e m p l a t e f o l d e r h e l l o \ B l u e p r i n t s p e c i f i c t e m p l a t e s s t a t i c \ S t a t i c f i l e s ( . c s s , . j s , e t c . ) h e l l o \ B l u e p r i n t _ _ i n i t _ _ . p y B l u e p r i n t c o n s t r u c t o r r o u t e s . p y B l u e p r i n t r o u t e s _ _ i n i t _ _ . p y A p p l i c a t i o n f a c t o r y t e s t s \ U n i t t e s t s p a c k a g e c o n f i g _ d e v e l o p m e n t . p y D e v e l o p m e n t c o n f i g u r a t i o n c o n f i g _ t e s t i n g . p y U n i t t e s t i n g c o n f i g u r a t i o n c o n f i g _ p r o d u c t i o n . p y P r o d u c t i o n c o n f i g u r a t i o n m a n a g e . p y L a u n c h s c r i p t The application package constructor exports a c r e a t e _ a p p ( ) factory function that creates application instances dynamically.
  26. Project Structure | Blueprints h e l l o _

    a p p \ R o o t f o l d e r a p p \ A p p l i c a t i o n p a c k a g e t e m p l a t e s \ T e m p l a t e f o l d e r h e l l o \ B l u e p r i n t s p e c i f i c t e m p l a t e s s t a t i c \ S t a t i c f i l e s ( . c s s , . j s , e t c . ) h e l l o \ B l u e p r i n t _ _ i n i t _ _ . p y B l u e p r i n t c o n s t r u c t o r r o u t e s . p y B l u e p r i n t r o u t e s _ _ i n i t _ _ . p y A p p l i c a t i o n f a c t o r y t e s t s \ U n i t t e s t s p a c k a g e c o n f i g _ d e v e l o p m e n t . p y D e v e l o p m e n t c o n f i g u r a t i o n c o n f i g _ t e s t i n g . p y U n i t t e s t i n g c o n f i g u r a t i o n c o n f i g _ p r o d u c t i o n . p y P r o d u c t i o n c o n f i g u r a t i o n m a n a g e . p y L a u n c h s c r i p t A blueprint sub-package contains a logical subset of the application routes, plus any modules that support them.
  27. Project Structure | Blueprints h e l l o _

    a p p \ R o o t f o l d e r a p p \ A p p l i c a t i o n p a c k a g e t e m p l a t e s \ T e m p l a t e f o l d e r h e l l o \ B l u e p r i n t s p e c i f i c t e m p l a t e s s t a t i c \ S t a t i c f i l e s ( . c s s , . j s , e t c . ) h e l l o \ B l u e p r i n t _ _ i n i t _ _ . p y B l u e p r i n t c o n s t r u c t o r r o u t e s . p y B l u e p r i n t r o u t e s _ _ i n i t _ _ . p y A p p l i c a t i o n f a c t o r y t e s t s \ U n i t t e s t s p a c k a g e c o n f i g _ d e v e l o p m e n t . p y D e v e l o p m e n t c o n f i g u r a t i o n c o n f i g _ t e s t i n g . p y U n i t t e s t i n g c o n f i g u r a t i o n c o n f i g _ p r o d u c t i o n . p y P r o d u c t i o n c o n f i g u r a t i o n m a n a g e . p y L a u n c h s c r i p t Templates for a blueprint are written in a sub-folder to avoid route name collisions between different blueprints.
  28. Project Structure | Unit Tests h e l l o

    _ a p p \ R o o t f o l d e r a p p \ A p p l i c a t i o n p a c k a g e t e m p l a t e s \ T e m p l a t e f o l d e r h e l l o \ B l u e p r i n t s p e c i f i c t e m p l a t e s s t a t i c \ S t a t i c f i l e s ( . c s s , . j s , e t c . ) h e l l o \ B l u e p r i n t _ _ i n i t _ _ . p y B l u e p r i n t c o n s t r u c t o r r o u t e s . p y B l u e p r i n t r o u t e s _ _ i n i t _ _ . p y A p p l i c a t i o n f a c t o r y t e s t s \ U n i t t e s t s p a c k a g e c o n f i g _ d e v e l o p m e n t . p y D e v e l o p m e n t c o n f i g u r a t i o n c o n f i g _ t e s t i n g . p y U n i t t e s t i n g c o n f i g u r a t i o n c o n f i g _ p r o d u c t i o n . p y P r o d u c t i o n c o n f i g u r a t i o n m a n a g e . p y L a u n c h s c r i p t Unit tests are written against your favorite unit testing package. A good option is the standard u n i t t e s t package from the Python standard library.
  29. Project Structure | Launch Script h e l l o

    _ a p p \ R o o t f o l d e r a p p \ A p p l i c a t i o n p a c k a g e t e m p l a t e s \ T e m p l a t e f o l d e r h e l l o \ B l u e p r i n t s p e c i f i c t e m p l a t e s s t a t i c \ S t a t i c f i l e s ( . c s s , . j s , e t c . ) h e l l o \ B l u e p r i n t _ _ i n i t _ _ . p y B l u e p r i n t c o n s t r u c t o r r o u t e s . p y B l u e p r i n t r o u t e s _ _ i n i t _ _ . p y A p p l i c a t i o n f a c t o r y t e s t s \ U n i t t e s t s p a c k a g e c o n f i g _ d e v e l o p m e n t . p y D e v e l o p m e n t c o n f i g u r a t i o n c o n f i g _ t e s t i n g . p y U n i t t e s t i n g c o n f i g u r a t i o n c o n f i g _ p r o d u c t i o n . p y P r o d u c t i o n c o n f i g u r a t i o n m a n a g e . p y L a u n c h s c r i p t A m a n a g e . p y script in the root folder is used to start the application and to run related tasks such as database maintenance or run the unit test suite.