Skip to content

Basic web application with Python and Flask


In this tutorial you will learn how to create simple web application with Python and Flask framework.


Create project (with PyCharm Community Edition)

In this project you will use PyCharm (in Community Edition)

PyCharm simplifies coding, but if you want, you can make this project without it and do some actions manualy from command line.

After launching PyCharm select New Project on Welcome screen:

and on the next screen select location to save it (in my case: /home/nosql/Pulpit/flask_basic_app)

and press Create to confirm your choice.

If you got this error while PyCharm creates your project:

please try this command:

and then restart PyCharm. After that I was able to create my project and run basic application:


Create initial Flask application

Add the following code to main.py file:

At this moment you will get an information, that some packages are missing so you should import all required package(s) - in this case only Flask:

When done, open terminal and activate your virtual environment:

Next set environment variables required by Flask:

Now you can run your application:

To verify if it realy runs, open a browser and type in the URL http://127.0.0.1:5000/ - you will see web page with Hello, World! printed on it; this confirms that your application is successfully running.


Flask uses a simple web server to serve our application in a development environment, which also means that the Flask debugger is running to make catching errors easier. This development server should not be used in a production deployment. While a Flask application’s development server is already running, it is not possible to run another Flask application with the same flask run command. This is because flask run uses the port number 5000 by default, and once it is taken, it becomes unavailable to run another application. To solve this problem, you have to either stop the server that is currently running pressing CTRL+C and then run flask run again, or if you want to run both applications at the same time, you can pass a different port number to the -p argument, for example, to run another application on port 5001 use the command: flask run -p 5001.

You can create initial Flask project directly from PyCharm. See the following links for details:


Templating

At this moment your application displays a simple message without any HTML. Using HTML is cool but Flask gives you something much more powerful: the Jinja template engine. This will make managing all your HTML much easier by writing pure HTML code in .htm files as well as enrich it with some logic.

Edit main.py file and put there the following code:

The index() view function returns the result of calling render_template() with index.htm as an argument. By default index.htm file should be located in the templates folder.
So, create a directory called templates inside your flask_basic_app directory:

Then inside it, create a file called index.htm:

and put there the following code:

In most cases web frameworks, besides directory dedicated to keep templates, use other directory for hosting static files, such as CSS files, JavaScript files, and images the application uses. It is no different in the case of Flask. Create a directory called static inside your main flask_basic_app directory and inside create another directory called css to host .css style files.

Inside css directory create style.css file and put there the following CSS rule:

Add a link to the style.css file inside the section of the index.htm template file:

Upon refreshing the main page of your application, you will notice that the text is now in brown, centered, and enclosed inside a border:

It's not surprisng that making another HTML file you will repeat most of the HTML code you already wrote in the index.htm template. You can avoid unproductive code repetition with the help of a base template file, which all of your HTML files will inherit from.

You can use the CSS language to style the application and make it more appealing using your own design. However, if you’re not a web designer, or if you aren’t familiar with CSS, then you can use the Bootstrap toolkit, which provides easy-to-use components for styling your application. In this project, we’ll use Bootstrap.

To make a base template, first create a file called base.htm inside your templates directory. Next paste into it an inital Bootstrap webpag code (see Get started with Bootstrap); using Bootstrap will make your app to look nice and allow you to save a lot of time needed to style the application and make it more appealing using your own design using pure CSS language:

When opened in web browser you will see:

Now change default Bootstrap template to the following form:

Although this code shouldn't be a problem for you, I will comment some elements so you will have better understanding of what you are doing:

  • is block that serves as a placeholder where you can put various contents according to your needs; in this case you will put here a title for each page in your application.
  • {{ url_for('index')}} is a call to a function that will return the URL for the required view function (index() in this case).
  • {% block content %} {% endblock %} is another block that will be replaced by main content of the page.

Now you have a base template (base.htm file) and you can take advantage of it using template inheritance - the ability to create new HTML files as an extended or "rebuilded" forms of "base" file. To do so, open the index.htm file and replace its contents with the following:

In this new version of the index.htm template, you use the {% extends %} tag to inherit from the base.htm template and extend it via replacing the content block in the base template with what is provided inside the content block in extension file.

Save and close the file and refresh the index page on your browser. You’ll see your page with a navigation bar and styled title:


Setting up the database

Now, you’ll set up a database to store your data. To make things simpler you’ll use a SQLite database to store your data. The sqlite3 module, which you will use to interact with the database, is readily available in the standard Python library.

First you need to create a table called bugs with the necessary columns. The simplest way is to create an .sql file that contains all SQL commands required to create table(s) with sample data and then use it to create the database.

Open a file called db.sql inside your flask_basic_app directory and put there the following code:

You can use this SQL file to create the database "manually" (for example with command line call) or use it in Python script where you will also add some data. In this case all data insertion statements will be hardcoded, but you can modify the code to read data to be inserted for axample from a CSV file.

Create a file named create_db.py inside the flask_basic_app directory and add there a following code:

You can run create_db.py simply from command line as you do with all regular Python files, or directly from PyCharm:

As e result, a new file called bugs.db will appear in your flask_basic_app directory. This means you’ve successfully set up your database.


Getting all data

Open the main.py file to make the set of modifications:

  • Import the sqlite3 module at the top of the main.py file:

  • In the main.py file create a function that creates a database connection and return it:

    Because you set the row_factory attribute to sqlite3.Row you will have name-based access to columns, which means that the database connection will return rows that behave like regular Python dictionary.

  • Modify the index() function to look like the following:

  • Open the index.htm file and change its contents to the following form:

Once you are done editing all the above files, navigate to the index page in your browser. On your page you’ll see two bugs you added to the database in create_db.py file:


Task for you: Change color of the badge; you may refere to this page Badges. Background colors.


Getting single data

In main.py file add the getBug() function:

You will use this function passing it a bug ID (via bugId argument) and receive back the bug associated with the provided ID. If the bug with specified ID does not exist, you will respond with a 404 Not Found message. To make it possible, you need to import the abort() function from the Werkzeug library, which was installed along with Flask, at the top of the main.py file:

Add the following view function to the main.py file:

In this view function, you add a variable rule to specify that the URL part after the slash / is a positive integer (marked with the int converter) that you need to access in this view function.

Create bug.htm template file and add there the following code:

This code is similar to the index.htm file, except that it displays a single bug data: creation date-time, title, type and its description.

You can now navigate to the following URLs to see the two bugs you have in your database: type in web browser's URL top field http://127.0.0.1:5000/1 or http://127.0.0.1:5000/2 and you will see expected bug:

If you specify nonexisting ID, for example http://127.0.0.1:5000/123, you will see:

Entering ID of bug is not very convenient and comfortable - it would be much better if you will jump to right URL as a result of selecting base bug info on index page. To satisfy this now you’ll make each post title link to its respective page. You’ll do this using the url_for()index.htm template for editing and change the value of the href attribute from # to {{ url_for('bugPage', bugId=bug['id']) }}:

The url_for()bugPage to the url_for() function as a first argument. This is the name of the bugPage() view function and since it accepts a bugId argument, you give it the value bug['id'].

The links on the index page will now function as expected:


Adding data

In this stage you will extend your code to allow adding data about new bugs. Because it is rather long section you will complete it in steps. First you will add form to enter required data and submit them to database. Next you will add a link to the navigation bar to have easy access to Add page and add functionality to display flashed messages.


Form to add data

Open the main.py file for editing and change import from:

to

You import:

  • The global request object to access incoming request data that will be submitted via an HTML form.
  • The url_for() function to generate URLs.
  • The flash() function to flash a message when a request is processed.
  • The redirect() function to redirect the client to a different location.

The flash() function stores flashed messages in the client’s browser session, which requires setting a secret key. This secret key is used to secure sessions, which allow Flask to store information from one request to another. The user can access the information stored in the session, but cannot modify it unless they have the secret key, so you must never allow anyone to access your secret key.

To set a secret key, you’ll add a SECRET_KEY configuration to your application via the app.config object. In main.py, just after the line:

add:

Create a view function to render a template that displays a form you can fill in to create a new bug note. Add this new function to the main.py file:

Next create the template file called add.htm inside your templates folder:

Use your browser to navigate to the /add route - you will see a Create a new bug note page with a fields for all required data:

This form submits a POST request to addBug() view function. At this moment, there is no code to handle a POST request in the function yet, so nothing happens after filling in the form and submitting it. To make it possible modify the addBug() view function to look exactly as follows:

In the above code you use typeOfBug name instead of simply type because latter shadows build-in name.

Navigate to the /add route using your web browser and fill in the form with all required data. Once you submit the form, you will see the new bug listed on the index page:


Edit the base.htmfile by adding a new <li> tag preceding the About link inside the <nav> tag (I marked new text you should add with [Begin: new code] and [End: new code] "tags"; of course you shouldn't copy these tags):


Then add a new for loop directly above the content block to display the flashed messages below the navigation bar. These messages are available in the special get_flashed_messages() function Flask provides:

After this change save and close the file. The navigation bar will now have a New bug item that links to the /add route.

If you try to add new bug with some informatin missing, you will see an error message:


Task for you: Modif the code so the type of bug is rather selected from drop-down list with predefined types then typed in text field.


Updating data

You will add a new route to the main.py file. View function associated with it will receive the ID of the bug that you want to update via URL in the format /update/BUG_ID with the bugId variable being the ID of the bug.

Add the following updateBug(bugId) view function to the main.py file. Because updating a bug is similar to creating a new one, so this view function will be very similar to the addBug() view function:

Save and close the file, then create a new update.htm template with the following code:

When you save template you can navigate to the following URL to update the first post:

You will see an Update "Add example" page:

Update the bug details, submit the form by pressing Save and make sure the post was updated:

The final step of updating is to add a link that points to the update page for each bug on the main index page. Make the following changes in the index.htm template file:

and test if everything work as expected:


Deleting data

This is a last step to obtain fully functional applicartion to maintaint your bugs. First, you’ll add a new route of the form /delete/ID that accepts POST requests, as you did to the updateBug(bugId) view function. Add the following code to the main.py file:

As you may notice, this view function accepts only POST requests. In consequence when you navigate directly to the /delete/BUG_ID route on your browser, you will get an error because web browsers default request is GET. In your application you solve this problem via a form that sends a POST request passing in the ID of the bug you want to delete.

Note that in this case you don’t render a template file because you’ll just add a Delete button directly to the main index page.

Open the index.htm template file:

You use the confirm() method to display a confirmation message before submitting the request.



Task for you: Change color of the flash message; you may refere to this page:


Task for you: Modif the app so you can manage predefined bug types.