Overview
Today, we will demonstrate how to create a simple web application using Flask
.
The application we will develop is a message bank. By the end, a user should be able to do two things on the application:
- Submit messages to the bank
- View a random sample of messages stored in the bank
1. Enable Submissions
First, we will create a base template, base.html
:
<!doctype html>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<h1>A Simple Message Bank</h1>
<title>{% block title %}{% endblock %}</title>
<nav>
<ul>
<li><a href="{{ url_for('submit') }}">Submit a message</a></li>
<li><a href="{{ url_for('view') }}">View messages</a></li>
</ul>
</nav>
<section class="content">
<!-- will be used for submit.html or view.html -->
<header>
{% block header %}{% endblock %}</header>
{% block content %}{% endblock %}</section>
We will also create submit.html
, which will extend
base.html
and contain the following elements:
- A text box for submitting a message.
- A text box for submitting the name of the user.
- A “submit” button.
Additionally, we will thank the user if a message is submitted.
{% extends 'base.html' %}
{% block header %}<h1>{% block title %}Submit{% endblock %}</h1>
{% endblock %}
{% block content %}<form method="post">
<label for="message">Your message: </label>
<br><br>
<input type="text" name="message" id="message">
<br><br>
<label for="handle">Your name or handle: </label>
<br><br>
<input type="text" name="handle" id="handle">
<br><br>
<input type="submit" value="Submit message">
</form>
{% if message %}<p>Thank you for the submission!</p>
{% endif %} {% endblock %}
So far, our combined page will look like this1:
Now, we will create a new file app.py
. The first function we will write in this file is get_message_db()
, which will handle creating the database of messages.
# import correct packages
from flask import Flask, render_template, request
from flask import redirect, url_for, abort, g
import sqlite3
import numpy as np
= Flask(__name__)
app
def get_message_db():
"""
Returns a database in the g attribute of the app with a table to host messages
"""
try:
return g.message_db # if the database exists
except:
= sqlite3.connect("messages_db.sqlite")
g.message_db # check if a table exists, create one if not
= 'CREATE TABLE IF NOT EXISTS messages(id INT, handle TEXT, message TEXT)'
cmd = g.message_db.cursor()
cursor
cursor.execute(cmd)return g.message_db
Next, we write a function insert_message(request)
, which will handle inserting a user’s message into the database.
def insert_message(request):
"""
insert a user message into the database
"""
= get_message_db() # connect to database
db = db.cursor()
cursor = 'SELECT COUNT(*) FROM messages'
cmd = cursor.execute(cmd).fetchone()[0] + 1 # set unique id for each message
new_id # use f-string
= f"INSERT INTO messages VALUES ({new_id}, '{request.form['handle']}', '{request.form['message']}')"
cmd
cursor.execute(cmd)# save row insertion
db.commit() db.close()
Finally, we will write a function submit()
to render_template()
the submit.html
template. In the instance of GET
method, we will just render submit.html
. In the instance of POST
, we will call on insert_message(request)
to record the message then render submit.html
.
@app.route("/", methods=['POST', 'GET'])
def submit():
"""
render submit.html from both GET and POST methods
"""
if request.method == 'GET':
return render_template('submit.html')
else:
= request.form['message']
message = request.form['handle']
handle # send to database
insert_message(request) return render_template('submit.html', message=message, handle=handle)
2. View Random Submissions
So far, we have the feature to submit and record a message. Now, the users should be able to view these messages.
We will write a function random_messages(n)
, which will return a collection of n
random messages from message_db
, or fewer if necessary.
def random_messages(n):
"""
return n random messages from the database or fewer if necessary
"""
= get_message_db()
db = db.cursor()
cursor = f"SELECT * FROM messages ORDER BY RANDOM() LIMIT {n}"
cmd = cursor.execute(cmd).fetchall()
messages
db.close()
return messages
Our final html
file will be view.html
, a page where we can view the random submissions.
{% extends 'base.html' %}
{% block header %}<h1>{% block title %}Some Cool Messages{% endblock %}</h1>
{% endblock %}
{% block content %}<ul>
{% for message in messages %}<p>{{message[2]}}</p>
<p>- <em>{{message[1]}}</em></p>
<br>
{% endfor %}</ul>
{% endblock %}
In the above file, the message
object is a tuple, where message[2]
contains the message and message[1]
contains the user handle.
Last but not least, we write a function view()
to render view.html
:
@app.route('/view/', methods=['POST', 'GET'])
def view():
"""
render view.html
"""
# picks a random integer from 1 to 5 (inclusive) and returns that many messages
= random_messages(np.random.randint(1,6))
messages return render_template('view.html', messages=messages)
3. Demo
To view our webapp, we will run the following command in the directory that houses all our files:
=development
export FLASK_ENV flask run
This will open the webapp locally. The first site rendered should be the exact same as Figure 1.
Now, suppose a user submits a message as shown below.
This message has now been sent to the database. Suppose more users visit the site to submit their messages.
If we were to go to view.html
via View Messages, we would see something like below:
We see 3 random messages that have been pulled from the database!
Appendix
Here is the code for style.css
that was used to customize the app:
, h1, h2, h3, h4, h5, h6, p, ul, ol, li {
bodymargin: 0;
padding: 0;
font-family: Arial, sans-serif;
}
body {background-color: #f5f5f5;
color: #333;
}
h1 {font-size: 32px;
font-weight: bold;
margin-bottom: 20px;
color: #007bff;
text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2);
text-align: center;
}
nav {background-color: #333;
color: #fff;
padding: 10px;
}
nav ul {list-style-type: none;
text-align: center;
}
nav li {display: inline-block;
margin-right: 10px;
}
nav a {color: #fff;
text-decoration: none;
}
:hover {
nav atext-decoration: underline;
}
.content {
margin: 20px;
}
header {text-align: center;
margin-bottom: 20px;
}
.block {
background-color: #fff;
padding: 20px;
border-radius: 4px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
}
.submit-link,
.view-link {
display: inline-block;
padding: 10px 20px;
background-color: #007bff;
color: #fff;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
text-decoration: none;
}
.submit-link:hover,
.view-link:hover {
background-color: #0056b3;
}