Introduction
In this post, I describe the process of building web applications using the Flask framework; we will create a website showing a random joke from a text file. We will learn about Jinja2 templates, static files, routing, and running Flask applications.
Python Flask
Flask is a lightweight web framework for Python designed to be simple and easy to use. It is widely used for developing web applications, RESTful APIs, and more.
Installation
You can install the Flask framework or any other Python package globally, which means the package will be available for any project on your computer or using a virtual environment, which we will also cover in this post.
Global installation
You can install the Flask package using pip:
pip install Flask
Installing a Python package using pip is typically installed globally unless you work in a virtual environment. A virtual environment is an isolated Python environment that allows you to manage dependencies for a specific project separately.
The global installation typically places the Flask package in the site-packages directory of the Python interpreter used by your system. The exact location may vary depending on your operating system and Python installation. Here are some typical locations:
- On Windows:
C:\Users\<Username>\AppData\Local\Programs\Python\Python<version>\Lib\site-packages
- On macOS/Linux:
/usr/lib/python<version>/site-packages
or/usr/local/lib/python<version>/site-packages
Remember that installing packages globally might lead to conflicts between different projects, especially if they require different versions of the same package. Virtual environments are recommended because they provide each project a clean and isolated environment.
PyCharm IDE
I am charmed with PyCharm, so I use it daily. You can easily install the Flask package and set up the interpreter following these steps:
- Create a Virtual Environment (Optional but Recommended):
- Open a terminal in PyCharm.
- Navigate to your project directory.
- Run the following command to create a virtual environment:
python3 -m venv venv
- Activate the virtual environment:
- On Windows:
venv\Scripts\activate
- On macOS/Linux:
source venv/bin/activate
- On Windows:
- Install Flask:
- With the virtual environment activated, use the following command to install Flask:
pip install Flask
- With the virtual environment activated, use the following command to install Flask:
- Configure PyCharm Interpreter:
- Open your project in PyCharm.
- Go to
File
>Settings
(orPyCharm
>Preferences
on macOS). - In the settings, navigate to
Project
>Project Interpreter
. - Click the gear icon and select
Add...
to add a new interpreter. - Choose
Existing environment
and point it to the Python interpreter within your virtual environment (venv
directory). - Click
OK
to confirm.
- Create a Flask Project in PyCharm (Optional):
- In PyCharm, go to
File
>New Project
. - Choose a location for your project and set the project type to
Flask
. - Select the Python interpreter you configured earlier.
- Click
Create
.
- In PyCharm, go to
- Run Flask Application:
- Open the Python file containing your Flask application in your Flask project.
- Look for a line that starts the Flask app, typically something like
app.run()
. - Right-click on this line and choose
Run <your_app_name>
.
- Test the Setup:
- Open a web browser and go to
http://localhost:5000
(or the URL specified in your Flask app). - You should see your Flask application running.
- Open a web browser and go to
Following these steps, you can add the Flask package to your PyCharm project and set up the interpreter correctly. If you encounter any issues, double-check your virtual environment, interpreter settings, and Flask installation.
Notice that when you choose to open a new Flask project, PyCharm will automatically create a “Hello World” application with a minimal configuration.
I also use the Tabnine plugin, which helps me do rapid prototyping.
What is venv?
venv
stands for “virtual environment,” a built-in Python module that supports creating lightweight, isolated Python environments. Virtual environments manage dependencies and avoid conflicts between projects requiring different versions of libraries or packages.
Here are some key points about venv
:
-
Isolation: A virtual environment allows you to create a self-contained environment with its own Python interpreter and package installations. This helps prevent conflicts between projects with different dependencies or versions.
-
Dependencies: When you activate a virtual environment, any packages you install using
pip
are installed only within that environment. This means you can have different versions of packages for other projects without affecting the global Python installation. -
Activation: To use a virtual environment, you need to activate it. On Windows, you typically run a script in the
Scripts
directory; on macOS/Linux, you use thesource
command. Activating a virtual environment changes your command or terminal prompt to indicate the active environment.- On Windows:
venv\Scripts\activate
- On macOS/Linux:
source venv/bin/activate
- On Windows:
- Creating a Virtual Environment: You can create a virtual environment using the following command:
python3 -m venv venv
This command creates a virtual environment named “venv” in the current directory.
- Deactivation: To deactivate a virtual environment and return to the global Python environment, you can use the
deactivate
command:deactivate
It’s important to note that venv
is available in Python 3.3 and later versions. In Python 3.3 to 3.6, venv
is included by default. In Python 3.7 and later, it is recommended to use venv
over the older virtualenv
package, as venv
has become more feature-rich and is included in the standard library.
Joker Flask App
This code is a simple example of a “Hello World” web application using Flask, a web framework for Python. We will use it as a starting point to create our Joker Web App. The Joker app will automatically show a random joke from a text file.
Herein, the “Hello World” web application was created with Flask.
# Import the Flask class from the Flask module
from flask import Flask
# Create an instance of the Flask class, usually named 'app'
app = Flask(__name__)
# Define a route for the root URL ('/'). When someone accesses the root URL, the function below is executed.
@app.route('/')
def hello_world():
# Return a simple string as the response when the root URL is accessed
return 'Hello, World!'
# The following block ensures that the app is only run when this script is executed directly, not when it's imported as a module
if __name__ == '__main__':
# Run the Flask app in debug mode, which provides additional information for debugging
app.run(debug=True)
Here’s a breakdown of the code:
-
from flask import Flask
: Imports the Flask class from the Flask module. -
app = Flask(__name__)
: Creates an instance of the Flask class. The__name__
argument determines the application’s root path. -
@app.route('/')
: Decorator that associates the functionhello_world
with the root URL (‘/’). Thehello_world
function is executed when someone accesses the root URL. -
def hello_world():
: Defines thehello_world
function, which will be called when the root URL is accessed. -
return 'Hello, World!'
: Returns a simple string (‘Hello, World!’) as the response when the root URL is accessed. -
if __name__ == '__main__':
: Checks if the script is being run directly, not imported as a module. -
app.run(debug=True)
: Runs the Flask development server. Thedebug=True
argument enables debugging mode, providing additional information for debugging purposes. The server listens on the default host and port (127.0.0.1:5000).
This code sets up a basic Flask web application with a single route that returns a “Hello, World!” message when the root URL is accessed.
Save the file and run the following command in your terminal:
python app.py
Visit http://127.0.0.1:5000/ in your web browser to see “Hello, World!”.
The warning message you’re seeing is a standard message generated by the Flask development server. It informs you that your server is unsuitable for production deployments and should only be used for development.
Flask’s built-in development server is single-threaded, not optimized for performance, and needs certain security features crucial in a production environment.
The message advises using a production-ready WSGI (Web Server Gateway Interface) server to deploy your Flask application in a production environment. Popular choices include Gunicorn, uWSGI, and mod_wsgi when using Apache.
Here’s an example of how you might run a Flask app with Gunicorn:
gunicorn -w 4 -b 0.0.0.0:5000 your_app:app
Replace your_app with the name of your Flask application file (without the “.py” extension).
Flask Routes
In Flask, routes define the endpoints of your application. Update your app.py
file and add the “/about” route:
# Import the Flask class from the Flask module
from flask import Flask
# Create an instance of the Flask class, usually named 'app'
app = Flask(__name__)
# Define a route for the root URL ('/'). When someone accesses the root URL, the function below is executed.
@app.route('/')
def hello_world():
# Return a simple string as the response when the root URL is accessed
return 'Hello, World!'
# Define another route for the '/about' URL. When someone accesses this URL, the following function is executed.
@app.route('/about')
def about():
# Return a different string as the response when the '/about' URL is accessed
return 'This is the about page.'
# The following block ensures that the app is only run when this script is executed directly, not when it's imported as a module
if __name__ == '__main__':
# Run the Flask app in debug mode, which provides additional information for debugging
app.run(debug=True)
Variable Rules in Routes
You can capture variables from the URL. Update your app.py
file:
# Import the Flask class from the Flask module
from flask import Flask
# Create an instance of the Flask class, usually named 'app'
app = Flask(__name__)
# Define a route for the root URL ('/'). When someone accesses the root URL, the function below is executed.
@app.route('/')
def hello_world():
# Return a simple string as the response when the root URL is accessed
return 'Hello, World!'
# Define another route for the '/about' URL. When someone accesses this URL, the following function is executed.
@app.route('/about')
def about():
# Return a different string as the response when the '/about' URL is accessed
return 'This is the about page.'
# Define a route for the '/user/<username>' URL. The '<username>' part is a variable that can take any value.
# The following function is executed When someone accesses this URL with a specific username.
@app.route('/user/<username>')
def show_user_profile(username):
# Return a string with the provided username in the response
return f'Hello {username}!'
# The following block ensures that the app is only run when this script is executed directly, not when it's imported as a module
if __name__ == '__main__':
# Run the Flask app in debug mode, which provides additional information for debugging
app.run(debug=True)
This code adds a new route, '/user/<username>'
. The <username>
part is a variable that can capture any value provided in the URL. For example, if someone accesses ‘/user/johndoe’, the show_user_profile
function will be executed with the argument username
set to ‘johndoe’. The function then returns a string that includes the provided username.
So, the updated application now has three routes:
- The root URL (‘/’) is handled by the
hello_world
function, which returns ‘Hello, World!’. - The ‘/user/
' URL is handled by the `show_user_profile` function, which dynamically includes the provided username in the response.
Visit http://127.0.0.1:5000/user/John in your browser to see the dynamic routing.
Templates and Static Files
Jinja2 Templates
Flask uses the Jinja2 templating engine.
Jinja2 is a designer-friendly templating engine for Python programming language. It is widely used in web development frameworks, and Flask, a popular Python web framework, uses Jinja2 as its default templating engine.
Here are some key points about Jinja2:
- Templating Engine:
- Jinja2 generates dynamic content in web applications by combining static HTML templates with dynamic data.
- It allows embedding dynamic elements, control structures (e.g., loops and conditionals), and expressions within HTML templates.
- Syntax:
- Jinja2 uses a simple and readable syntax. Variables, expressions, and control structures are enclosed in double curly braces for output and curly braces with percentage signs for control statements.
- Integration with Flask:
- Flask integrates Jinja2 as its default templating engine. When you use
render_template
in Flask, it processes the Jinja2 template and renders the HTML with dynamic content.
- Flask integrates Jinja2 as its default templating engine. When you use
- Dynamic Content:
- You can insert dynamic content into templates using placeholders, which are replaced with actual values when the template is rendered.
Here’s a simple example of Jinja2 syntax:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
</head>
<body>
<h1>{{ greeting }}</h1>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
In this example:
{{
and}}
are placeholders for dynamic content.{%for item in items%} ... {% endfor %}
is a control structure that iterates over a list of items.
Jinja2 is not limited to Flask and can be used with other Python frameworks. Its simplicity and flexibility make it popular for generating dynamic content in various web applications.
Create a templates
folder in your project directory and add a file named index.html
, a simple HTML document that likely serves as a template for rendering dynamic content. Below is an explanation and comments for each part of the HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Set the character set for the document -->
<meta charset="UTF-8">
<!-- Ensure proper rendering and compatibility with Internet Explorer -->
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<!-- Define the viewport settings for responsive design -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Set the title of the HTML document using the Flask variable 'title' -->
<title>{{ title }}</title>
</head>
<body>
<!-- Display the value of the Flask variable 'message' within an H1 element -->
<h1>{{ message }}</h1>
</body>
</html>
Here’s the breakdown:
-
<!DOCTYPE html>
: Declares the document type and HTML version being used. -
<html lang="en">
: Specifies the root element of the HTML document and sets the language attribute to English. -
<head>
: Contains meta-information about the HTML document, such as character set, viewport settings, and the document title.-
<meta charset="UTF-8">
: Defines the character set as UTF-8, which supports a wide range of characters. -
<meta http-equiv="X-UA-Compatible" content="IE=edge">
: Ensures compatibility with Internet Explorer by specifying the latest rendering engine. -
<meta name="viewport" content="width=device-width, initial-scale=1.0">
: Sets the viewport properties for responsive design. -
<title>{{ title }}</title>
: Sets the title of the HTML document dynamically using the Flask variable ‘title’.
-
-
<body>
: Contains the content of the HTML document that will be displayed in the browser.<h1>{{ message }}</h1>
: Displays the value of the Flask variable ‘message’ within an H1 (heading level 1) element.
This template is designed to receive dynamic content from a Flask application, specifically the title
and message
variables, and display them in the HTML document when rendered.
The use of double curly braces ({{ variable_name }}
) indicates placeholders for dynamic content that will be provided by the Flask application.
Update your app.py
file to use this template:
# Import the Flask class and render_template function from the flask module
from flask import Flask, render_template
# Create an instance of the Flask class, usually named 'app'
app = Flask(__name__)
# Define a route for the root URL ('/'). When someone accesses the root URL, the function below is executed.
@app.route('/')
def hello_world():
# Use the render_template function to render an HTML template named 'index.html'
# The template is rendered with the provided title and message variables
return render_template('index.html', title='Home', message='Hello, World!')
# The following block ensures that the app is only run when this script is executed directly, not when it's imported as a module
if __name__ == '__main__':
# Run the Flask app in debug mode, which provides additional information for debugging
app.run(debug=True)
In this code, the Flask application renders an HTML template using the render_template
function. Here are the key points:
-
render_template
function is used to render HTML templates. It takes the name of the template file (‘index.html’ in this case) and any additional variables that should be passed to the template. -
'index.html'
: This is the name of the HTML template file. The template file should be in a folder named ‘templates’ within the same directory as your Flask application. -
title='Home', message='Hello, World!'
: These are the variables passed to the template. The template will use these variables to customize its content in this example. -
The HTML template file (‘index.html’) is not provided in the code snippet, but it would typically include placeholders for the
title
andmessage
variables.
This code is useful when you want to separate your HTML code from your Python code, allowing you to create dynamic web pages by passing data from your Python application to the HTML templates.
Static Files
Flask static files refer to files, such as stylesheets, scripts, images, or other assets, that are served directly to the client (web browser) without being processed by the Flask application. These files are considered “static” because their content doesn’t change dynamically based on user requests; they remain the same for every user and request.
In a typical Flask application, static files are stored in the “static directory”. This directory is a conventional location for placing files that must be served directly to clients. The structure of a Flask project might look like this:
/project
/static
/css
style.css
/js
script.js
/img
image.jpg
/templates
index.html
app.py
CSS (Cascading Style Sheets): is a style sheet language used to describe the presentation of a document written in HTML or XML. It defines how elements are displayed on a screen, in print, or in other media.
CSS allows you to control your web pages’ layout, colours, fonts, and other visual aspects.
Create a static
folder in your project directory and add a stylesheet, e.g., styles.css
. Update your index.html
file to include this stylesheet:
<head>
<!-- other meta tags -->
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
Here’s an elementary example of a style.css
file for your Flask app. This example adds some minimal styling to the index.html
file you provided earlier:
/* style.css */
/* Apply styles to the body element */
body {
font-family: 'Arial', sans-serif; /* Set the font family for the entire body */
margin: 20px; /* Add a margin of 20 pixels around the body */
background-color: black; /* Set the background color to black*/
}
/* Style the H1 element */
h1 {
color: forestgreen; /* Set the text color of H1 to forestgreen */
text-align: center; /* Center-align the text within the H1 element */
}
This style.css
file includes:
- Styling for the
body
element, setting the font-family, background color and margin. - Styling for the
h1
element, setting the text colour and alignment.
You can link this style.css
file to your index.html
by adding the following line within the <head>
section of your HTML file:
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='style.css') }}">
Place the style.css
file in a folder named static
within your Flask project directory. The url_for('static', filename='style.css')
is a Flask function that generates a URL for the static file.
Request and Forms
Flask provides a request
object to handle incoming data. Update your app.py
:
# Import the Flask class and render_template from the flask module
from flask import Flask, render_template
# Create an instance of the Flask class, usually named 'app'
app = Flask(__name__)
# Define a route for the '/greeting' URL, allowing both GET and POST requests
@app.route('/greeting', methods=['GET', 'POST'])
def greeting():
# Check if the request method is POST
if request.method == 'POST':
# If it is a POST request, retrieve the 'username' from the form data
username = request.form['username']
# Return a personalized greeting using the submitted username
return f'Hello, {username}!'
# If it's a GET request, render the 'login.html' template
return render_template('greeting.html')
# The following block ensures that the app is only run when this script is executed directly, not when it's imported as a module
if __name__ == '__main__':
# Run the Flask app in debug mode, which provides additional information for debugging
app.run(debug=True)
Create a greeting.html
file in the templates
folder:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Login</title>
</head>
<body>
<form method="post">
<label for="username">Username:</label>
<input type="text" id="username" name="username" required>
<button type="submit">Hello</button>
</form>
</body>
</html>
The greeting.html file is a simple HTML form with a text input for the username. When the form is submitted, the entered username is sent to the server, and the Flask app responds with a personalized greeting.
- @app.route(‘/greeting’, methods=[‘GET’, ‘POST’]): This route handles GET and POST requests to the ‘/greeting’ URL. GET requests to render the greeting form, and POST requests take form submissions.
- if request.method == ‘POST’:: Checks if the request method is POST. If it is, it means the form has been submitted.
- username = request.form[‘username’]: Retrieves the ‘username’ from the submitted form data.
- return f’Hello, {username}!’: Returns a personalized greeting using the submitted username.
- return render_template(‘greeting.html’): Renders the ‘greeting.html’ template for GET requests.
So, let’s run the code. Yes, we got our first error, “Internal Server Error”! It sounds terrifying, but fear not my fellow coder; it is okay.
If you open your eyes and look at the scary message “NameError: name ‘request’ is not defined”, you will see that we just forgot to import ‘request’ from the flask package.
This can be fixed:
# Import the Flask class, render_template, and request (that we missed)
# from the flask module
from flask import Flask, render_template, request
Flask App with a Random Joke
Create a file named jokes.txt
with some jokes. Update your app.py
with the following:
# Import the Flask class, render_template, and request from the flask module
from flask import Flask, render_template, request
# Import the random module for generating random values
import random
# Create an instance of the Flask class, usually named 'app'
app = Flask(__name__)
# Define a route for the root URL ('/'). When someone accesses the root URL, the function below is executed.
@app.route('/')
def hello_world():
# Use the render_template function to render an HTML template named 'index.html'
# The template is rendered with the provided title and message variables
return render_template('index.html', title='Home', message='Hello, World!')
# Define a function to get a random joke from a file
def get_random_joke():
# Open the 'jokes.txt' file in read mode
with open('jokes.txt', 'r') as file:
# Read all lines from the file and store them in a list
jokes = file.readlines()
# Return a randomly chosen joke from the list
return random.choice(jokes)
# Define a route for the '/joke' URL
@app.route('/joke')
def random_joke():
# Call the get_random_joke function to retrieve a random joke
joke = get_random_joke()
# Render the 'joke.html' template with the retrieved joke
return render_template('joke.html', joke=joke)
# Define a route for the '/greeting' URL, allowing both GET and POST requests
@app.route('/greeting', methods=['GET', 'POST'])
def greeting():
# Check if the request method is POST
if request.method == 'POST':
# If it is a POST request, retrieve the 'username' from the form data
username = request.form['username']
# Return a personalized greeting using the submitted username
return f'Hello, {username}!'
# If it's a GET request, render the 'login.html' template
return render_template('greeting.html')
# The following block ensures that the app is only run when this script is executed directly, not when it's imported as a module
if __name__ == '__main__':
# Run the Flask app in debug mode, which provides additional information for debugging
app.run(debug=True)
# Define another route for the '/about' URL. When someone accesses this URL, the following function is executed.
@app.route('/about')
def about():
# Return a different string as the response when the '/about' URL is accessed
return 'This is the about page.'
# Define a route for the '/user/<username>' URL. The '<username>' part is a variable that can take any value.
# The following function is executed When someone accesses this URL with a specific username.
@app.route('/user/<username>')
def show_user_profile(username):
# Return a string with the provided username in the response
return f'Hello {username}!'
# The following block ensures that the app is only run when this script is executed directly, not when it's imported as a module
if __name__ == '__main__':
# Run the Flask app in debug mode, which provides additional information for debugging
app.run(debug=True)
This code defines a simple Flask application that serves a random joke from a file when the ‘/joke’ URL is accessed. Here’s a brief summary of each part:
-
import random
: Import therandom
module for generating random values. -
from flask import Flask, render_template
: Import theFlask
class andrender_template
function from the Flask module. -
app = Flask(__name__)
: Create an instance of the Flask class, usually named ‘app’. -
def get_random_joke(): ...
: Define a function namedget_random_joke
that reads jokes from a file and returns a randomly chosen joke. -
@app.route('/joke')
: Define a route for the ‘/joke’ URL. -
def random_joke(): ...
: Define a function namedrandom_joke
that callsget_random_joke
to retrieve a random joke and then renders the ‘joke.html’ template with the joke. -
if __name__ == '__main__': ...
: Run the Flask app in debug mode if the script is executed directly.
This script assumes the existence of a file named ‘jokes.txt’ in the same directory, where each file line contains a joke. The get_random_joke
function reads these jokes and returns one randomly. The joke
route then renders a template (‘joke.html’) with the retrieved joke.
Create a joke.html
file in the templates
folder:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Random Joke</title>
</head>
<body>
<h1>{{ joke }}</h1>
</body>
</html>
Now, you can visit http://127.0.0.1:5000/joke to see a random joke from the jokes.txt
file.
We can also rewrite the joke.html and request another random joke from the file. Add these lines to the joke.html:
<form method="get" action="{{ url_for('joke') }}">
<button type="submit">Get Another Joke</button>
</form>
I’ve added a “form” element with the method=”get” attribute and an action attribute that points to the /joke route.
Inside the form, there’s a button with the label “Get Another Joke.” When the button is clicked, the form is submitted, and the /joke route is triggered, refreshing the page with a new random joke.
Final touches
I made minor corrections to allow the user to transition from the root URL (‘/’) to greeting and then (‘/joke’) and altered some CSS to make it more pleasant. You can do anything; the code is in the GitHub repository flask-random-joke.
chatGPT prompts
Even though I have some prior experience with Flask, I have used chatGPT to quickly write code and create jokes.txt files. It saved me a lot of time.
You can also use chatGPT for your coding; it is a fantastic learning tool. However, often, you will have to adapt and rerun the prompts to achieve the desired result.
Herein is my prompts list:
Output 200 strings containing concise and funny Computer science, machine learning, AI, and Python coding jokes
Rewrite random_joke.html and add a button to refresh the page and show another joke
Write me a CSS style to centre this button and make it beautiful
Add comments and explain the code I am going to add next
Write the simplest style.css for this Flask app
Explain and add comments to this code
Conclusion
Congratulations! We have created a simple Flask app that greets users and makes jokes. We also learned about essential concepts such as static files, templates and routes.
Feel free to explore more advanced features and enhance your Flask application with new functionality. Let me know how it works.
Did you like this post? Please let me know if you have any comments or suggestions.
Python posts that might be interesting for youLinks
About Elena Elena, a PhD in Computer Science, simplifies AI concepts and helps you use machine learning.
|