Flask Web Development

Developing Web Applications with Python

Take full creative control of your web applications with Flask, the Python-based microframework. With this hands-on book, you’ll learn Flask from the ground up by developing a complete social blogging application step-by-step.

If you have some previous Python experience, this book shows you how to take advantage of the creative freedom Flask gives you.

Example Code

The book centers around the development of Flasky, a social blogging application released as open source under the MIT license. You are welcome to review the project on GitHub at https://github.com/miguelgrinberg/flasky.

Below you can see some screenshots:



Home page



Profile page

Table Of Contents

Part I. Introduction to Flask 1. Installation Using Virtual Environments Installing Python Packages with pip 2. Basic Application Structure Initialization Routes and View Functions Server Startup A Complete Application Flask Extensions The Request-Response Cycle 3. Templates The Jinja2 Template Engine Twitter Bootstrap Integration with Flask-Bootstrap Custom Error Pages Links Static Files Localization of Dates and Times with Flask-Moment 4. Web Forms Cross-Site Request Forgery (CSRF) Protection Form Classes HTML Rendering of Forms Form Handling in View Functions Redirects and User Sessions Message Flashing 5. Databases SQL Databases NoSQL Databases SQL or NoSQL? Python Database Frameworks Database Management with Flask-SQLAlchemy Database Use in View Functions Integration with the Python Shell Database Migrations with Flask-Migrate 6. Emails Email Support with Flask-Mail 7. Large Application Structure Project Structure Configuration Options Application Package Launch Script Unit Tests Requirements File Database Setup

Part II. Example: A Social Blogging Application

8. User Authentication Authentication Extensions for Flask Password Security Creating an Authentication Blueprint User Authentication with Flask-Login New User Registration Account Confirmation Account Management



9. User Roles Database Representation of Roles Role Assignment Role Verification



10. User Profiles Profile Information User Profile Page Profile Editor User Avatars



11. Blog Posts Blog Post Submission and Display Blog Posts in Profile Pages Paginating Long Lists of Blog Posts Rich Text Posts with Markdown and Flask-PageDown Permanent Links to Blog Posts Blog Post Editor



12. Followers Database Relationships Revisited Followers in the Profile Page Query Followed Posts using a Database Join Show Followed Posts in the Home Page



13. User Comments Database Representation of Comments Comment Submission and Display Comment Moderation



14. Application Programming Interfaces (APIs) Introduction to REST RESTful Web Services with Flask

Part III. The Last Mile

15. Testing Obtaining Code Coverage Reports The Flask Test Client End-to-End Testing with Selenium Is It Worth It?



16. Performance Logging Slow Database Performance Source Code Profiling



17. Deployment Deployment Workflow Logging of Errors In Production Cloud Deployment The Heroku Platform Traditional Hosting



18. Additional Resources Using an Integrated Development Environment Finding Flask Extensions Getting Involved with Flask



Errata

The following corrections apply to the first and second releases of the first edition of the book. If you have something else to report please contact the author at flaskbookfeedback@gmail.com.

Several chapters

The recommended syntax to import a Flask extension has changed since the book was published. Instead of using from flask.ext.extension import Something it is now recommended that from flask_extension import Something is used. The Flasky code repository on GitHub has been updated to reflect this.





The recommended syntax to import a Flask extension has changed since the book was published. Instead of using it is now recommended that is used. The Flasky code repository on GitHub has been updated to reflect this. Chapter 3, Section "Custom Error Pages"

In this section, two custom error page routes are defined, for the 404 and 500 status codes respectively. Later in the section, only the template for the 404 error is shown. The text does not mention that a similar template should be created for the 500 error code. (Reported by Martin Betz)





In this section, two custom error page routes are defined, for the 404 and 500 status codes respectively. Later in the section, only the template for the 404 error is shown. The text does not mention that a similar template should be created for the 500 error code. Chapter 3, Example 3-12

The text around this code example does not clearly specify where in the template file this snippet must be inserted. The location of this snippet does not really matter, because this represents a template block defined by the parent template. (Reported by Martin Betz)





The text around this code example does not clearly specify where in the template file this snippet must be inserted. The location of this snippet does not really matter, because this represents a template block defined by the parent template. Chapter 3

At the end of the chapter, the language selection feature of Flask-Moment is presented, but it isn't clearly explained where in the template the the language selection primitive needs to be specified. The location should be right after the moment.js library is imported. (Reported by Martin Betz)





At the end of the chapter, the language selection feature of Flask-Moment is presented, but it isn't clearly explained where in the template the the language selection primitive needs to be specified. The location should be right after the moment.js library is imported. Chapter 8, Section "User Authentication with Flask-Login"

Unfortunately version 0.3.0 of Flask-Login introduced changes that break applications that were coded against the 0.2.x versions. More specifically, the User.is_authenticated , User.is_active and User.is_anonymous methods were converted to properties. To port the code to the new release of Flask-Login it is necessary to remove the () when these are accessed. The Flasky repository has been updated to work with the current release. (Reported by several readers)





Unfortunately version 0.3.0 of Flask-Login introduced changes that break applications that were coded against the 0.2.x versions. More specifically, the , and methods were converted to properties. To port the code to the new release of Flask-Login it is necessary to remove the when these are accessed. The Flasky repository has been updated to work with the current release. Chapter 8, Example 8-10

This example code uses the texts "Sign In" and "Sign Out", but the screenshots in this chapter and the code repository use "Log In" and "Log Out". (Reported by Farhad Fouladi)





This example code uses the texts "Sign In" and "Sign Out", but the screenshots in this chapter and the code repository use "Log In" and "Log Out". Chapter 11, Example 11-14

The pathname printed in the heading of this example is incorrect. The correct pathname is app/templates/index.html . (Reported by Trevor Christiansen)





The pathname printed in the heading of this example is incorrect. The correct pathname is . Chapter 11, Example 11-21

The redirect in this code example uses the expression url_for('post', id=post.id) . The first argument to the url_for function should instead be '.post' , the dot indicates the route should be located in the current blueprint. (Reported by Henry Thiel)





The redirect in this code example uses the expression . The first argument to the function should instead be , the dot indicates the route should be located in the current blueprint. Chapter 12, Example 12-8

The route decorator in this code example should be main.route . (Reported by Libin Feng)





The route decorator in this code example should be . Chapter 13, Example 13-4

The calculation of the page number of the comment uses the / division operator, which has different behavior in Python 2 and Python 3. In this situation integer division is the desired operator, so using // provides the correct output in both versions of Python. (Reported by Kevin Labtani and Serhii Ivashchenko)





The calculation of the page number of the comment uses the division operator, which has different behavior in Python 2 and Python 3. In this situation integer division is the desired operator, so using provides the correct output in both versions of Python. Chapter 14, Example 14-4

The pathname printed in the heading of this example is incorrect.The correct pathname is app/api_1_0/errors.py . (Reported by Trevor Christiansen)





The pathname printed in the heading of this example is incorrect.The correct pathname is . Chapter 14, Example 14-9

The generate_auth_token method returns a byte string, without decoding it to a string. The correct return expression for this function is s.dumps({'id': self.id}).decode('ascii') . (Reported by Samuel Woodward)





The method returns a byte string, without decoding it to a string. The correct return expression for this function is . Chapter 14, Example 14-12

The code example is missing a comma. The correct code example is printed below:



class Post(db.Model): # ... def to_json(self): json_post = { 'url': url_for('api.get_post', id=self.id, _external=True), 'body': self.body, 'body_html': self.body_html, 'timestamp': self.timestamp, 'author': url_for('api.get_user', id=self.author_id, _external=True), 'comments': url_for('api.get_post_comments', id=self.id, _external=True), 'comment_count': self.comments.count() } return json_post (Reported by Trevor Christiansen)





The code example is missing a comma. The correct code example is printed below: Chapter 14, Example 14-13

The code example incorrectly references the api.get_post route. The correct route in this example is api.get_user . (Reported by Trevor Christiansen)





The code example incorrectly references the route. The correct route in this example is . Chapter 14, Example 14-17

The auth.login_required decorator included in the two routes presented in this code example are not needed, since authentication is taken care of globally for the blueprint. (Reported by Trevor Christiansen)





The decorator included in the two routes presented in this code example are not needed, since authentication is taken care of globally for the blueprint. Chapter 14, Table 14-13

The 6th row in the table has a syntax error in the first column. The correct route is /posts/<int:id>/comments . (Reported by Trevor Christiansen and Samuel Woodwward)





The 6th row in the table has a syntax error in the first column. The correct route is . Chapter 15, Example 15-5

The reference to the get_auth_header function is incorrect. The correct function is get_api_headers . (Reported by Samuel Woodward)





The reference to the function is incorrect. The correct function is . Chapter 16, Section "Source Code Profiling"

The --profile-dir should be --profile_dir . (Reported by Serhii Ivashchenko)





The should be . Chapter 17, Section "Provisioning a Database"

The command to create a Heroku Postgres database has changed since the book went to print. The updated command is heroku addons:create heroku-postgresql:hobby-dev (Reported by Norbert Stüken)





The following corrections apply only to the first release of the first edition of the book, and were corrected in the second release.