Tutorial: Get started with the Flask web framework in Visual Studio

Applies to: yesVisual Studio noVisual Studio for Mac

Note

This article applies to Visual Studio 2017. If you're looking for the latest Visual Studio documentation, see Visual Studio documentation. We recommend upgrading to the latest version of Visual Studio. Download it here

Flask is a lightweight Python framework for web applications that provides the basics for URL routing and page rendering.

Flask is called a "micro" framework because it doesn't directly provide features like form validation, database abstraction, authentication, and so on. Such features are instead provided by special Python packages called Flask extensions. The extensions integrate seamlessly with Flask so that they appear as if they're part of Flask itself. For example, Flask itself doesn't provide a page template engine. Templating is provided by extensions such as Jinja and Jade, as demonstrated in this tutorial.

In this tutorial, you learn how to:

  • Create a basic Flask project in a Git repository using the "Blank Flask Web Project" template (step 1).
  • Create a Flask app with one page and render that page using a template (step 2).
  • Serve static files, add pages, and use template inheritance (step 3).
  • Use the Flask Web Project template to create an app with multiple pages and responsive design (step 4).
  • Use the Polls Flask Web Project template to create a polling app that uses various storage options (Azure storage, MongoDB, or memory).

Over the course of these steps you create a single Visual Studio solution that contains three separate projects. You create the project using different Flask project templates that are included with Visual Studio. By keeping the projects in the same solution, you can easily switch back and forth between different files for comparison.

Note

This tutorial differs from the Flask Quickstart in that you learn more about Flask as well as how to use the different Flask project templates that provide a more extensive starting point for your own projects. For example, the project templates automatically install the Flask package when creating a project, rather than needing you to install the package manually as shown in the Quickstart.

Prerequisites

Flask project templates are included with all earlier versions of Python Tools for Visual Studio, though details might differ from what's discussed in this tutorial.

Python development isn't presently supported in Visual Studio for Mac. On Mac and Linux, use the Python extension in Visual Studio Code tutorial.

Step 1-1: Create a Visual Studio project and solution

Step 1-2: Examine the Git controls and publish to a remote repository

Question: What are some advantages of using source control from the beginning of a project?

Answer: Using source control from the start, especially if you also use a remote repository, provides a regular offsite backup of your project. Unlike maintaining a project just on a local file system, source control also provides a complete change history and the easy ability to revert a single file or the whole project to a previous state. That change history helps determine the cause of regressions (test failures). Source control is essential if multiple people are working on a project, because it manages overwrites and provides conflict resolution. Source control is fundamentally a form of automation, sets you up well for automating builds, testing, and release management. It's the first step in using DevOps for a project, and because the barriers to entry are so low, there's really no reason to not use source control from the beginning.

For further discussion on source control as automation, see The Source of Truth: The Role of Repositories in DevOps, an article in MSDN Magazine written for mobile apps that applies also to web apps.

Question: Can I prevent Visual Studio from auto-committing a new project?

Answer: Yes. To disable auto-commit, go to the Settings page in Team Explorer, select Git > Global settings, clear the option labeled Commit changes after merge by default, then select Update.

Step 1-3: Create the virtual environment and exclude it from source control

Now that you've configured source control for your project, you can create the virtual environment the necessary Flask packages that the project requires. You can then use Team Explorer to exclude the environment's folder from source control.

Question: Why do I want to create a virtual environment?

Answer: A virtual environment is a great way to isolate your app's exact dependencies. Such isolation avoids conflicts within a global Python environment, and aids both testing and collaboration. Over time, as you develop an app, you invariably bring in many helpful Python packages. By keeping packages in a project-specific virtual environment, you can easily update the project's requirements.txt file that describes that environment, which is included in source control. When the project is copied to any other computers, including build servers, deployment servers, and other development computers, it's easy to recreate the environment using only requirements.txt (which is why the environment doesn't need to be in source control). For more information, see Use virtual environments.

Question: How do I remove a virtual environment that's already committed to source control?

Answer: First, edit your .gitignore file to exclude the folder: find the section at the end with the comment # Python Tools for Visual Studio (PTVS) and add a new line for the virtual environment folder, such as /BasicProject/env. (Because Visual Studio doesn't show the file in Solution Explorer, open it directly using the File > Open > File menu command. You can also open the file from Team Explorer: on the Settings page, select Repository Settings, go to the Ignore & Attributes Files section, then select the Edit link next to .gitignore.)

Second, open a command window, navigate to the folder like BasicProject that contains the virtual environment folder such as env, and run git rm -r env. Then commit those changes from the command line (git commit -m 'Remove venv') or commit from the Changes page of Team Explorer.

Step 1-4: Examine the boilerplate code

  1. Once project creation completes, you see the solution and project in Solution Explorer, where the project contains only two files, app.py and requirements.txt:

    Blank Flask project files in Solution Explorer

  2. As noted earlier, the requirements.txt file specifies the Flask package dependency. The presence of this file is what invites you to create a virtual environment when first creating the project.

  3. The single app.py file contains three parts. First is an import statement for Flask, creating an instance of the Flask class, which is assigned to the variable app, and then assigning a wsgi_app variable (which is useful when deploying to a web host, but not used for now):

    from flask import Flask
    app = Flask(__name__)
    
    # Make the WSGI interface available at the top level so wfastcgi can get it.
    wsgi_app = app.wsgi_app
    
  4. The second part, at the end of the file, is a bit of optional code that starts the Flask development server with specific host and port values taken from environment variables (defaulting to localhost:5555):

    if __name__ == '__main__':
        import os
        HOST = os.environ.get('SERVER_HOST', 'localhost')
        try:
            PORT = int(os.environ.get('SERVER_PORT', '5555'))
        except ValueError:
            PORT = 5555
        app.run(HOST, PORT)
    
  5. Third is a short bit of code that assigns a function to a URL route, meaning that the function provides the resource identified by the URL. You define routes using Flask's @app.route decorator, whose argument is the relative URL from the site root. As you can see in the code, the function here returns only a text string, which is enough for a browser to render. In the steps that follow you render richer pages with HTML.

    @app.route('/')
    def hello():
        """Renders a sample page."""
        return "Hello World!"
    

Question: What is the purpose of the name argument to the Flask class?

Answer: The argument is the name of the app's module or package, and tells Flask where to look for templates, static files, and other resources that belong to the app. For apps contained in a single module, __name__ is always the proper value. It's also important for extensions that need debugging information. For more information, and additional arguments, see the Flask class documentation (flask.pocoo.org).

Question: Can a function have more than one route decorator?

Answer: Yes, you can use as many decorators as you want if the same function serves multiple routes. For example, to use the hello function for both "/" and "/hello", use the following code:

@app.route('/')
@app.route('/hello')
def hello():
    """Renders a sample page."""
    return "Hello World!"

Question: How does Flask work with variable URL routes and query parameters?

Answer: In a route, you mark any variable with <variable_name>, and Flask passes the variable to the function using a named argument in the URL path. For example, a route in the form of /hello/<name> generates a string argument called name to the function. Query parameters are available through the request.args property, specifically through the request.args.get method. For more information, see The Request object in the Flask documentation.

# URL: /hello/<name>?message=Have%20a%20nice%20day
@app.route('/hello/<name>')
def hello(name):
    msg = request.args.get('message','')
    return "Hello " + name + "! "+ msg + "."

To change the type, prefix the variable with int, float, path (which accepts slashes to delineate folder names), and uuid. For details, see Variable rules in the Flask documentation.

Question: Can Visual Studio generate a requirements.txt file from a virtual environment after I install other packages?

Answer: Yes. Expand the Python Environments node, right-click your virtual environment, and select the Generate requirements.txt command. It's good to use this command periodically as you modify the environment, and commit changes to requirements.txt to source control along with any other code changes that depend on that environment. If you set up continuous integration on a build server, you should generate the file and commit changes whenever you modify the environment.

Step 1-5: Run the project

  1. In Visual Studio, select Debug > Start Debugging (F5) or use the Web Server button on the toolbar (the browser you see might vary):

    Run web server toolbar button in Visual Studio

  2. Either command assigns a random port number to the PORT environment variable, then runs python app.py. The code starts the app using that port within Flask's development server. If Visual Studio says Failed to start debugger with a message about having no startup file, right-click app.py in Solution Explorer and select Set as Startup File.

  3. When the server starts, you see a console window opens that displays the server log. Visual Studio then automatically opens a browser to http://localhost:<port>, where you should see the message rendered by the hello function:

    Flask project default view

  4. When you're done, stop the server by closing the console window, or by using the Debug > Stop Debugging command in Visual Studio.

Question: What's the difference between using the Debug menu commands and the server commands on the project's Python submenu?

Answer: In addition to the Debug menu commands and toolbar buttons, you can also launch the server using the Python > Run server or Python > Run debug server commands on the project's context menu. Both commands open a console window in which you see the local URL (localhost:port) for the running server. However, you must manually open a browser with that URL, and running the debug server doesn't automatically start the Visual Studio debugger. You can attach a debugger to the running process later, if you want, using the Debug > Attach to Process command.

Next steps

At this point, the basic Flask project contains the startup code and page code in the same file. It's best to separate these two concerns, and to also separate HTML and data by using templates.

Go deeper