Elena' s AI Blog

Joking Flask App

10 Dec 2023 / 39 minutes to read

Elena Daehnhardt


Midjourney, December 2023


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:

  1. 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
  2. Install Flask:
    • With the virtual environment activated, use the following command to install Flask:
      pip install Flask
      
  3. Configure PyCharm Interpreter:
    • Open your project in PyCharm.
    • Go to File > Settings (or PyCharm > 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.
  4. 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.
  5. 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>.
  6. 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.

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.

Interpreter Settings, adding a package

Interpreter Settings, adding a package

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:

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

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

  3. 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 the source 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
      
  4. 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.

  5. 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:

  1. from flask import Flask: Imports the Flask class from the Flask module.

  2. app = Flask(__name__): Creates an instance of the Flask class. The __name__ argument determines the application’s root path.

  3. @app.route('/'): Decorator that associates the function hello_world with the root URL (‘/’). The hello_world function is executed when someone accesses the root URL.

  4. def hello_world():: Defines the hello_world function, which will be called when the root URL is accessed.

  5. return 'Hello, World!': Returns a simple string (‘Hello, World!’) as the response when the root URL is accessed.

  6. if __name__ == '__main__':: Checks if the script is being run directly, not imported as a module.

  7. app.run(debug=True): Runs the Flask development server. The debug=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!”.

Flask Hello World!e

Flask 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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 and message 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.

Joker app got a Style

Joker App got a Style

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.

Yes, our allegedly first Internal Server Error!

Yes, our allegedly first Internal Server Error!

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 the random module for generating random values.

  • from flask import Flask, render_template: Import the Flask class and render_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 named get_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 named random_joke that calls get_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 you


Links

  1. Flask Documentation

  2. Flask Quickstart

  3. Flask Routing

  4. The Request Object

  5. Jinja Documentation

  6. Flask render_template

  7. CSS Introduction

  8. CSS Tutorial - W3Schools

  9. New Chat (chatGPT by OpenAI)

desktop bg dark

About Elena

Elena, a PhD in Computer Science, simplifies AI concepts and helps you use machine learning.




Citation
Elena Daehnhardt. (2023) 'Joking Flask App', daehnhardt.com, 10 December 2023. Available at: https://daehnhardt.com/blog/2023/12/10/python-flask-app/
All Posts