Flask Web Development

Buy from:

An Introduction to Flask

Buy from:

Building Web APIs with Flask

Buy from:

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
      • 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


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.

  • 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)

  • 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)

  • 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)

  • 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)

  • 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)

  • 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)

  • 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)

  • Chapter 12, Example 12-8
    The route decorator in this code example should be main.route. (Reported by Libin Feng)

  • 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)

  • 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)

  • 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)

  • 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,
                'comments': url_for('api.get_post_comments', id=self.id,
                'comment_count': self.comments.count()
        return json_post
    (Reported by Trevor Christiansen)

  • 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)

  • 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)

  • 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)

  • 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)

  • Chapter 16, Section "Source Code Profiling"
    The --profile-dir should be --profile_dir. (Reported by Serhii Ivashchenko)

  • 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.

  • Chapter 3, Example 3-3
    The URL of the first route is incorrectly shown as /index, while the correct URL is /. (Reported by Farhad Fouladi)

  • Chapter 4, Section "HTML Rendering of Forms"
    The punctuation in the first sentence is incorrect. The correct sentence should read "Form fields are callables that, when invoked from a template, render themselves to HTML.". (Reported by Ken Hommel)

  • Chapter 4, Section "HTML Rendering of Forms"
    The first two code examples in this section show how to render a form in a template, but are incomplete as they do not show how to implement CSRF protection. The corrected examples are shown below:

    <form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name() }}
    {{ form.submit() }}
    <form method="POST">
    {{ form.hidden_tag() }}
    {{ form.name.label }} {{ form.name(id='my-text-field') }}
    {{ form.submit() }}
    The {{ form.hidden_tag() }} line adds a hidden field to the form where Flask-WTF stores the CSRF token. Note that CSRF support is included in Flask-Bootstrap's `wtf.quick_form()` macro, so this is only needed when rendering forms manually. (Reported by Richard Milne)

  • Chapter 4, Example 4-3
    The text that follows the example incorrectly indicates that the format of a Jinja2 conditional is {% if variable %}...{% else %}...{% endif %}, but really should have used the term condition instead of variable. (Reported by Marco Agner)

  • Chapter 4, Example 4-6
    In this example the line of code that reads form.name.data = '' should not be in this function, as it has no effect. (Reported by Steven Marcatante)

  • Chapter 5, Example 5-4
    The pathname printed in the heading of this example is incorrect. The correct pathname is hello.py. (Reported by Napoleon)

  • Chapter 6, Table 6-1
    The configuration variable that stores the email server hostname is incorrect. The correct variable is MAIL_SERVER. (Reported by Christian Hettlage)

  • Chapter 7, Example 7-5
    A dot is missing in the import statement that imports the blueprint. The correct import statement is from .main import main as main_blueprint. (Reported by Erik de Wildt)

  • Chapter 8, Example 8-9
    The example does not import the Length validator. The import line that imports the validators is: from wtforms.validators import Required, Length, Email. (Reported by Ken Hommel and Dan Carpenter)

  • Chapter 8, Example 8-20
    The pathname printed in the heading of this example is incorrect. The correct pathname is app/templates/auth/email/confirm.txt. (Reported by John Baham, Jr.)

  • Chapter 8, Example 8-22
    The before_request() handler was coded to deny any requests outside of the auth blueprint, but this effectively prevents static files from being served. Normally this isn't a problem because the static files were already cached in the client web browser, but a correct handler is shown below:
    def before_request():
        if current_user.is_authenticated() \
                and not current_user.confirmed \
                and request.endpoint[:5] != 'auth.' \
                and request.endpoint != 'static':
            return redirect(url_for('auth.unconfirmed'))
    This change allows static files such as image, Javascript and CSS files to be served to unconfirmed users. (Reported by Michael Graupner)

  • Chapter 8, Example 8-22
    The redirect() call in route unconfirmed() is incorrectly printed. The correct line is return redirect(url_for('main.index')). (Reported by Arne Wiese)

  • Chapter 8, Example 8-23
    The correct code example is shown below:
    def resend_confirmation():
    token = current_user.generate_confirmation_token()
    send_email(current_user.email, 'Confirm Your Account',
    'auth/email/confirm', user=current_user, token=token)
    flash('A new confirmation email has been sent to you by email.')
    return redirect(url_for('main.index'))
    The version printed in the book has an incorrect argument list in the call to the `send_email()` function. (Reported by Wang Yandong)

  • Chapter 9, Example 9-6
    The code example is missing one import: from .models import Permission. (Reported by Jonathan Kapelus)

  • Chapter 10, Example 10-8
    The code example contains a typo. The line that reads db.session.add(user) should be db.session.add(current_user). (Reported by Lukasz Gabrych)

  • Chapter 11, Example 11-15, and Chapter 12, Examples 12-3, 12-7, 12-10, 12-11
    The pathname printed in the heading of these examples is incorrect. The correct pathname is app/models.py. (Reported by John Baham, Jr.)

  • Chapter 14, section "Creating an API Blueprint"
    The filenames of some of the files in the api_1_0 folder are in singular, while they should be plural to match the source code on GitHub. These are users.py, posts.py and comments.py. (Reported by John Baham, Jr.)

  • Chapter 15, Example 15-5
    The "write a post" portion of the test includes an incorrect body string that does not have correct Markdown styling. The correct sentence should be data = json.dumps ({ 'body' : 'body of the *blog* post' })). (Reported by Dmitry Zhuravlev-Nevsky)

An Introduction to Flask

First Steps in Web Development with Python

Get started with Flask, the popular web framework that’s small, lightweight, and powerful. This video tutorial uses use short and simple examples to help beginning Python developers explore the features of Flask and some of its extensions.

You’ll learn topics central to most web applications such as routing, templates, web forms, and user sessions, along with a brief introduction to databases and user logins. By the end of the class unit testing and application deployment are also explored.

The approximate duration of this course is 4 hours and 17 minutes. The first two chapters are available to watch for free at oreilly.com.

Example Code

This course features a variety of example projects that demonstrate specific features of the Flask framework or its related extensions. You are welcome to browse through the source code.

Table Of Contents

  1. Introduction
    • Welcome and Set Up
  2. Hello, Flask!
    • A Simple "Hello World" Application
  3. Templates
    • Introduction to Templates
    • Using Jinja2 Templates
    • Using Flask-Bootstrap
    • Custom Error Pages
    • Page Links
  4. Web Forms
    • Working with Web Forms
    • Form Management and Validation with Flask-WTF
    • Rendering Forms with Flask-Bootstrap
    • File Uploads
  5. Flask In Depth
    • Understanding Contexts
    • Request Dispatching
    • Request Hooks
    • Responses
  6. Databases
    • Using Flask-SQLAlchemy
  7. User Logins
    • Password Security
    • Using Flask-Login
  8. Scalable Application Structure
    • Scalable Application Structure
  9. Testing
    • Writing Unit Tests & Code Coverage
    • End-to-end testing with the Flask Test Client
  10. Deployment
    • Running in Production Mode
    • Deploying to Heroku
    • Deploying to a Linux Server

Building Web APIs with Flask

Techniques for Developing Modern Web Services with Python

If you want to build web services and APIs, this video course shows you how to do it with Flask, the popular web framework that’s small, lightweight, and powerful. Using detailed examples, Miguel Grinberg shows you how to create APIs for database backed services as well as Internet enabled devices.

The approximate duration of this course is 3 hours and 32 minutes. The first two chapters are available to watch for free at oreilly.com.

Example Code

This course is structured around two example API projects:

  • orders: a service that exposes an orders database to clients.
  • camera: a service that allows clients to take and view pictures and timelapse sequences. This project is designed to run on a Raspberry Pi with a camera module, but can also run in emulation mode in a regular computer without specialized camera hardware.

You are welcome to browse through the source code.

Table Of Contents

  1. Introduction
    • Welcome and Setup
    • API Demonstration
  2. Implementing APIs with Flask
    • Basic CRUD Implementation
    • Relationships Between Resources
    • Error Handling
    • Working with Hardware Devices
  3. Security
    • Password Authentication
    • Token Authentication
  4. Testing
    • Writing Tests with the Flask Test Client
    • Obtaining Test Coverage Metrics
  5. Advanced API Practices
    • Project Structure for Larger Projects
    • Implementing Custom Decorators for Flask Routes
    • Simplifying Responses
    • Paginating Resource Collections
    • HTTP Caching
    • Rate Limiting API Access
    • Asynchronous Tasks

Copyright ©2014 by Miguel Grinberg. All rights reserved. This web site is independently owned and operated by Miguel Grinberg.