Build a Dictionary App with Flask
Build a Flask web app with SQLite to search, add, edit, and delete words.
Introduction
30 Second Summary
Think about how often you look up a word and forget it the next day. What if you had your own personal dictionary app where you could save words, search them instantly, and manage your growing vocabulary collection?
In this project, you will build a Dictionary Manager web application using Python and Flask. Your app will let you search for words, add new definitions, edit existing ones, and delete entries you no longer need.
What You'll Build
You type a word into the search bar on your homepage and instantly see matching definitions pulled from your database. On the dashboard, you add new vocabulary, tweak meanings, or remove words entirely.
By the end of this project, you'll have:
- A live search page where you type a word and see matching definitions appear from your SQLite database.
- A management dashboard where you add new words, edit their meanings, and delete entries you no longer want.
- A reusable template system using Jinja2 inheritance so your pages share a common layout with a navigation bar.
- A styled interface with CSS that makes your app look polished and professional in the browser.
- Secret Mission: Add a "Word of the Day" feature that displays a random word from your dictionary on the homepage.
Are there any prerequisites?
None. This guide walks you through installing Python, VS Code, and Flask from scratch. You do not need any prior coding experience to get started.
Before We Start
Before We Start...
Before we dive in, let's lock in what you're about to build and why it matters. This step is your moment to commit to the goal before any hands-on work begins.
Set Up Your Development Environment
Every project starts with the right tools in place. Before you can write any Python code or build a web app, you need Python itself installed, a code editor to write in, and the Flask framework ready to go.
In this step, you will install Python 3.14.6, set up VS Code as your code editor, and create an isolated project environment with Flask installed inside it.
In this step, get ready to:
- Install Python 3.14.6 and VS Code on your machine.
- Create a project folder with a virtual environment.
- Install Flask 3.1.3 inside the virtual environment.
Install Python and VS Code
Python is the programming language that powers your Flask web app. You need version 3.14 or higher for this project.
- Press the Windows key to open your search bar.
- Type PowerShell and press Enter to open it.
- Check if Python is already installed by running this command:
python --version
✔️ I see Python 3.14 or higher
Python is ready to go. Close PowerShell and skip ahead to the VS Code installation below.
ⓧ I see an older version
You have Python installed, but it is an older version that will not work for this project. You need to install Python 3.14.6 alongside it.
- Open your browser and go to python.org/downloads.
- Click the Download Python 3.14.6 button.
- Run the downloaded python-3.14.6-amd64.exe installer.
- On the first screen, check the box that says Add python.exe to PATH.
- Click Install Now.
- Close PowerShell and reopen it (press the Windows key, type PowerShell, press Enter).
- Run python --version again to confirm it now shows Python 3.14.6.
Old version still showing?
If the old version still appears after reinstalling, the new Python path needs to come first in your system PATH. Open Settings, search for Environment Variables, and move the Python 3.14 entry above any older Python entries in the Path variable.
ⓧ Command not found
Python is not installed yet. Let's install it now.
- Open your browser and go to python.org/downloads.
- Click the Download Python 3.14.6 button.
- Run the downloaded python-3.14.6-amd64.exe installer.
- On the first screen, check the box that says Add python.exe to PATH. This is critical.
- Click Install Now.
- Once complete, close PowerShell and reopen it.
- Run python --version to confirm it prints Python 3.14.6.
Still seeing an error?
Make sure you checked Add python.exe to PATH during installation. If you missed it, run the installer again, select Modify, and ensure the PATH option is checked.
help me fix Python not being recognised in my terminal
Now let's install VS Code, the code editor you will use for this entire project.
- Open your browser and go to code.visualstudio.com/download.
- Click the Windows button to download the User Setup installer.
- Run the downloaded installer and follow the prompts to complete the installation.
- Press the Windows key to open your search bar.
- Type Visual Studio Code and press Enter to open it.
VS Code opens with a Welcome tab. You are ready to start building.
What is VS Code?
VS Code is a free code editor made by Microsoft. It has a built-in terminal, file explorer, and extensions for Python development. You will write all your code and run all your commands inside VS Code from this point on.
Create your project folder and virtual environment
A virtual environment is an isolated space where you install packages for one project without affecting anything else on your machine. This keeps your project's dependencies clean and predictable.
- In VS Code, open the built-in terminal by pressing Ctrl+` (the backtick key, above Tab).
- Move to your Desktop by running this command:
cd ~/Desktop
- Create your project folder and move into it by running these commands:
mkdir dictionary-app
cd dictionary-app
- Confirm you are inside the folder by running:
pwd
You should see a path ending in dictionary-app, like C:\Users\YourName\Desktop\dictionary-app.
- Create a virtual environment by running this command:
python -m venv venv
- Activate the virtual environment by running this command:
venv\Scripts\activate
You should see (venv) appear at the beginning of your terminal prompt. This confirms the virtual environment is active.
What is a virtual environment?
Think of a virtual environment as a sealed box for your project's packages. When you install Flask inside this box, it does not affect any other Python project on your computer.
The (venv) prefix in your terminal tells you the box is open and active. Any pip install command you run now goes into this environment only.
Seeing a script execution error?
If PowerShell shows an error about running scripts being disabled, you need to allow script execution. Run this command first:
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
Then try venv\Scripts\activate again.
help me activate my Python virtual environment on Windows
Install Flask
Flask is a lightweight Python web framework. It gives you the tools to handle web requests, serve HTML pages, and connect to a database. All from a single Python file.
- Install Flask inside your virtual environment by running this command:
pip install Flask==3.1.3
You will see pip downloading and installing Flask along with its dependencies. When it finishes, you will see a success message.
Why pin the version?
The ==3.1.3 part locks the exact version of Flask you install. This ensures your project works the same way every time, even if a newer version is released later.
Before you run the next command, what do you expect to see in the output?
- Verify Flask is installed correctly by running this command:
flask --version
You should see output that includes Flask 3.1.3 along with your Python version. This confirms everything is installed and working.
Flask command not found?
Make sure your virtual environment is still active. Look for (venv) at the start of your terminal prompt. If it is missing, run venv\Scripts\activate again before retrying.
help me fix Flask not being found after installing it
Your development environment is fully set up. Next, you will write your first Flask app and see it running in the browser.
Create Your First Running Flask App
You have Python, VS Code, and Flask ready to go. Now you need to confirm they all work together before building any real features.
In this step, you will create the skeleton of your web app. A single Python file, a pair of HTML templates, and a stylesheet. By the end, you will have a page loading in your browser that proves Flask is serving your code.
In this step, get ready to:
- Create the project folder structure with separate directories for templates and static files.
- Write a Flask app with a route that renders an HTML page.
- Style the page with CSS and confirm everything loads in the browser.
Create the project folders and write your Flask app
Flask expects a specific folder layout. Templates (your HTML files) go in a folder called templates. Static assets (CSS, JavaScript) go in a folder called static.
- Create both folders inside your dictionary-app folder by running these commands:
mkdir templates
mkdir static
- Confirm the folders exist by running:
ls
You should see templates and static listed alongside your venv folder.
Don't see the folders?
Make sure your terminal is inside the dictionary-app folder. Run cd on its own to check your current location. If you are somewhere else, navigate back with cd ~/Desktop/dictionary-app.
help me find my dictionary-app folder in the terminal
Now you will create the main Python file that runs your entire application.
- Create a new file called app.py in the root of your dictionary-app folder. In VS Code, click the new file icon at the top of the Explorer sidebar, type app.py, and press Enter.
- Paste the following code into app.py:
import sqlite3
from flask import Flask, render_template, request, redirect, url_for, flash, g
app = Flask(__name__)
app.secret_key = 'your-secret-key-here'
DATABASE = 'dictionary.db'
@app.route('/')
def index():
return render_template('index.html', results=[], query='')
if __name__ == '__main__':
app.run(debug=True)
What does this code do?
- app = Flask(__name__) creates your Flask application instance.
- @app.route('/') tells Flask to run the index() function when someone visits the homepage.
- render_template('index.html', results=[], query='') loads an HTML file and passes data to it.
- app.run(debug=True) starts the web server and auto-reloads when you change code.
- Save app.py with Ctrl+S.
Write the HTML templates
Flask uses Jinja2 for templates. You will create a base layout that every page shares, then a child template that fills in page-specific content.
- Create a new file called base.html inside the templates folder. In the Explorer sidebar, right-click the templates folder, select New File, type base.html, and press Enter.
- Paste the following code into base.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{% block title %}Dictionary Manager{% endblock %}</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
</head>
<body>
<nav>
<a href="{{ url_for('index') }}">Search</a>
<a href="{{ url_for('dashboard') }}">Dashboard</a>
</nav>
<main>
{% with messages = get_flashed_messages() %}
{% if messages %}
{% for message in messages %}
<div class="flash">{{ message }}</div>
{% endfor %}
{% endif %}
{% endwith %}
{% block content %}{% endblock %}
</main>
<script src="{{ url_for('static', filename='script.js') }}"></script>
</body>
</html>
What is template inheritance?
The {% block content %}{% endblock %} tag defines a placeholder. Child templates fill this placeholder with their own content while keeping the nav bar and stylesheet link from the base.
This means you write the nav and page structure once, and every page in your app reuses it automatically.
- Save base.html.
- Create another new file inside templates called index.html. Right-click the templates folder again, select New File, and name it index.html.
- Paste the following code into index.html:
{% extends "base.html" %}
{% block title %}Search - Dictionary Manager{% endblock %}
{% block content %}
<h1>Dictionary Search</h1>
<form method="GET" action="{{ url_for('index') }}">
<input type="text" name="query" placeholder="Search for a word..." value="{{ query }}">
<button type="submit">Search</button>
</form>
{% endblock %}
What does this template do?
- {% extends "base.html" %} tells Jinja2 to wrap this page inside the base layout.
- {% block content %} fills the placeholder from base.html with the search form.
- value="{{ query }}" keeps the search box filled with whatever the user typed.
- Save index.html.
Your templates are ready. Before adding styles, test that Flask can serve the page.
- Start the Flask server by running this command in your terminal:
python app.py
You will see an error page in your browser at this point. That is expected.
Why do I see a BuildError?
The base template references a dashboard route that does not exist yet. Flask cannot generate a URL for a route that has not been defined.
You will add the dashboard route in Step 4. For now, add a temporary placeholder so the page loads. In app.py, add this route directly above the if __name__ line:
@app.route('/dashboard')
def dashboard():
return 'Dashboard coming soon'
Save app.py. The server auto-reloads in debug mode. Refresh your browser and you should now see the unstyled page with a nav bar and search form.
- Open your browser and go to http://127.0.0.1:5000.
You should see an unstyled page with two nav links (Search, Dashboard), a heading that says "Dictionary Search", and a search form. The layout is plain because there is no CSS yet.
Still seeing an error?
Make sure you added the temporary dashboard route and saved app.py. Check your terminal for error messages. Common issues include a typo in a filename (index.html must be inside the templates folder, not the project root) or a missing {% extends "base.html" %} line at the top of index.html.
help me fix my Flask app error
Style the application with CSS
The page works but looks bare. Adding a stylesheet transforms it into something polished. You will also add a JavaScript placeholder file that the base template already links to.
- Create a new file called script.js inside the static folder. Right-click the static folder, select New File, and name it script.js.
- Paste this placeholder into script.js:
// Dictionary Manager - JavaScript
// This file is linked in base.html for any future interactivity
console.log('Dictionary Manager loaded');
- Save script.js.
- Create another file in the static folder called style.css. Right-click static, select New File, and name it style.css.
- Start by adding the global reset, body layout, and navigation styles. Paste this into style.css:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
background-color: #f5f5f5;
}
nav {
background-color: #333;
padding: 15px;
margin-bottom: 30px;
border-radius: 5px;
}
nav a {
color: white;
text-decoration: none;
margin-right: 20px;
font-weight: bold;
}
nav a:hover {
color: #ddd;
}
What do these styles do?
- The * selector resets all margins and padding so every browser starts from the same baseline.
- max-width: 800px and margin: 0 auto center the page content.
- The nav styles create a dark bar with white links at the top of every page.
- Save style.css and refresh your browser.
You should see the dark navigation bar appear at the top with white "Search" and "Dashboard" links. The page background turns light grey.
- Add the heading, form, and button styles below the existing CSS in style.css:
h1 {
color: #333;
margin-bottom: 20px;
}
h2 {
color: #555;
margin-top: 30px;
margin-bottom: 15px;
}
form {
margin-bottom: 20px;
}
input[type="text"] {
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
font-size: 16px;
margin-right: 10px;
}
button {
padding: 10px 20px;
background-color: #333;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
}
button:hover {
background-color: #555;
}
What do these styles do?
These rules style the search input with rounded corners, a subtle border, and comfortable padding. The button matches the nav bar colour scheme so the whole page feels consistent.
- Save style.css and refresh your browser.
The search form now has a polished input field and a dark button. The heading text is properly spaced.
- Add the remaining styles for feedback messages, search results, and table layout below the existing CSS in style.css:
.delete-btn {
background-color: #cc3333;
}
.delete-btn:hover {
background-color: #ee5555;
}
.flash {
background-color: #d4edda;
color: #155724;
padding: 10px 15px;
border-radius: 4px;
margin-bottom: 20px;
}
.results li {
list-style: none;
padding: 10px;
margin-bottom: 5px;
background-color: white;
border-radius: 4px;
border: 1px solid #ddd;
}
.no-results {
color: #666;
font-style: italic;
}
What do these styles do?
- .flash creates a green notification banner for success messages.
- .results li gives each search result a card-like appearance with a white background and border.
- .delete-btn makes the delete button red so it stands out as a destructive action.
- Add the final table styles at the bottom of style.css:
table {
width: 100%;
border-collapse: collapse;
margin-top: 10px;
}
th, td {
padding: 12px;
text-align: left;
border-bottom: 1px solid #ddd;
}
th {
background-color: #333;
color: white;
}
.inline-form {
display: inline;
margin: 0;
}
- Save style.css.
These table styles will take effect once you build the dashboard in a later step. For now, all the CSS your app needs is in place.
Before you refresh, what do you expect to see on the page?
- Refresh your browser at http://127.0.0.1:5000.
You should see a styled page with a dark navigation bar showing "Search" and "Dashboard" links, a "Dictionary Search" heading, and a search form with a rounded input field and dark button.
✔️ I see the styled page with nav bar and search form
Your Flask app is serving templates and static files correctly. The full skeleton is working.
ⓧ The page looks unstyled or the CSS is not loading
Check that your style.css file is inside the static folder (not templates or the project root). The file name must match exactly what base.html references: style.css.
Try a hard refresh with Ctrl+Shift+R to clear cached files. If styles still do not load, open your browser's developer tools (F12) and check the Console tab for 404 errors on style.css.
help me debug why my Flask static CSS file is not loading
✔️ Awesome, I've got everything!
Great. Double check you have saved all five files before moving on.
ⓧ I'd like to double check the full code
Scroll up and confirm each of these files is present and saved in your project:
- app.py in the project root (the Flask app with the / route and temporary /dashboard route).
- templates/base.html (the shared layout with nav, flash messages, and content block).
- templates/index.html (the search page extending base.html).
- static/style.css (all four CSS chunks combined in order).
- static/script.js (the three-line placeholder).
Your app skeleton is alive. You have a Flask server, a template system, and a styled frontend all working together. Next up, you will give the search form something to actually search by connecting a database.
Build the Database and Search Feature
Your Flask app loads in the browser with a search form, but clicking Search does nothing useful yet. The form submits, but there is no database behind it to store or look up words.
In this step, you will connect a SQLite database to your app and wire up the search form so it queries real data. By the end, you will have a working search feature. But you will immediately hit a new problem: the database is empty, so every search returns nothing.
In this step, get ready to:
- Create a database schema file that defines your words table.
- Add helper functions that connect your Flask app to SQLite.
- Update the search route and template to query the database and display results.
Create the database schema file
A schema file tells SQLite what tables and columns to create. You will define a single table called words with three columns: an auto-incrementing ID, the word itself, and its meaning.
- Create a new file called schema.sql in your dictionary-app folder (the same level as app.py) by running this command in your terminal:
New-Item schema.sql
- Open schema.sql in VS Code and paste in this SQL definition:
CREATE TABLE IF NOT EXISTS words (
id INTEGER PRIMARY KEY AUTOINCREMENT,
word TEXT NOT NULL,
meaning TEXT NOT NULL
);
What does this SQL do?
- CREATE TABLE IF NOT EXISTS words creates a table called words only if it does not already exist.
- id INTEGER PRIMARY KEY AUTOINCREMENT gives each row a unique number that counts up automatically.
- word TEXT NOT NULL and meaning TEXT NOT NULL store the vocabulary word and its definition. Neither can be empty.
- Save schema.sql.
- Confirm the file exists by running:
ls
You should see schema.sql listed alongside app.py, the templates folder, and the static folder.
Don't see schema.sql?
Make sure your terminal is inside the dictionary-app folder, not a subfolder like templates. Run cd ~/Desktop/dictionary-app to get back to the right place.
Help me find where schema.sql ended up
Add database helper functions to your app
Flask needs functions to open a database connection, close it when a request finishes, and initialize the tables from your schema file. You will add these as reusable helpers in app.py.
- In app.py, find the blank line below DATABASE = 'dictionary.db'.
- Add the following two functions directly below that line:
def get_db():
# Get or create a database connection for this request
db = getattr(g, '_database', None)
if db is None:
db = g._database = sqlite3.connect(DATABASE)
db.row_factory = sqlite3.Row
return db
@app.teardown_appcontext
def close_connection(exception):
# Automatically close the database when the request ends
db = getattr(g, '_database', None)
if db is not None:
db.close()
What do these functions do?
- get_db() checks if a database connection already exists for this request. If not, it creates one. db.row_factory = sqlite3.Row lets you access columns by name (like row['word']) instead of by number.
- close_connection() runs automatically after every request thanks to the @app.teardown_appcontext decorator. It closes the database connection so you never leak open connections.
- Below close_connection(), add the init_db() function that creates your tables:
def init_db():
# Create the database tables from schema.sql
with app.app_context():
db = get_db()
with app.open_resource('schema.sql', mode='r') as f:
db.cursor().executescript(f.read())
db.commit()
What does init_db do?
This function opens schema.sql, reads the SQL inside it, and executes it against the database. The result is a fresh words table ready to store your vocabulary.
app.open_resource() looks for the file in the same directory as app.py. That is why schema.sql must live at the project root.
CREATE TABLE IF NOT EXISTS means this is safe to run every time the app starts. It will not overwrite existing data.
- Now find the if __name__ == '__main__': block at the bottom of app.py.
- Find this line:
if __name__ == '__main__':
app.run(debug=True)
- Add init_db() above app.run(debug=True), so the block now looks like this:
if __name__ == '__main__':
init_db()
app.run(debug=True)
- Save app.py.
- Run your app to test that the database gets created:
python app.py
You should see the Flask development server start with output showing Running on http://127.0.0.1:5000.
- Stop the server by pressing Ctrl+C in the terminal.
- Confirm the database file was created by running:
ls
You should now see dictionary.db listed alongside your other files. That is your SQLite database file, created automatically by init_db().
Don't see dictionary.db?
Check that you added init_db() inside the if __name__ == '__main__': block, before app.run(debug=True). If it is outside this block or misspelled, the function never runs.
Also confirm that schema.sql is in the same folder as app.py. If Flask cannot find it, the app will crash with a FileNotFoundError.
My app crashes when I run it after adding init_db
Wire up the search route and template
The database exists, but the search form still does not use it. You need to update the index route to read what the user typed, query the database, and pass the results to the template.
- In app.py, find the existing index() route function. It currently looks like this:
@app.route('/')
def index():
return render_template('index.html', results=[], query='')
- Replace the entire index() function with this updated version:
@app.route('/')
def index():
results = []
query = request.args.get('query', '')
if query:
db = get_db()
results = db.execute(
'SELECT * FROM words WHERE word LIKE ?',
('%' + query + '%',)
).fetchall()
return render_template('index.html', results=results, query=query)
What does this route do now?
- request.args.get('query', '') reads the search term from the URL. When you submit the form, Flask puts the value in the URL as ?query=yourword.
- The if query: check means the database is only queried when the user actually types something.
- SELECT * FROM words WHERE word LIKE ? searches for partial matches. The % wildcards around the query mean typing "app" would match "apple", "application", or "happy".
- The ? placeholder protects against SQL injection by letting SQLite safely insert the user's input.
- Save app.py.
- Now open templates/index.html and find the closing </form> tag.
- Add the following template code below </form> and above {% endblock %}:
{% if query %}
{% if results %}
<h2>Results for "{{ query }}"</h2>
<ul class="results">
{% for row in results %}
<li>
<strong>{{ row['word'] }}</strong>: {{ row['meaning'] }}
</li>
{% endfor %}
</ul>
{% else %}
<p class="no-results">No words found matching "{{ query }}".</p>
{% endif %}
{% endif %}
What does this template code do?
- {% if query %} only shows results when the user has searched for something. On first page load, nothing appears below the form.
- {% if results %} checks whether any matching words came back from the database.
- {% for row in results %} loops through each matching word and displays it as a list item.
- The {% else %} branch shows a "No words found" message when the search returns zero results.
- Save templates/index.html.
Seeing a Jinja2 syntax error?
Make sure every {% if %} has a matching {% endif %}. The template uses nested conditionals, so you need two {% endif %} tags at the end. Also check that the new code sits between </form> and {% endblock %}.
Help me fix a Jinja2 template error in index.html
✔️ Awesome, I've got everything!
Great. Make sure you have saved both app.py and templates/index.html.
ⓧ I'd like to double check the full code
Here is templates/index.html in full:
{% extends "base.html" %}
{% block title %}Search - Dictionary Manager{% endblock %}
{% block content %}
<h1>Dictionary Search</h1>
<form method="GET" action="{{ url_for('index') }}">
<input type="text" name="query" placeholder="Search for a word..." value="{{ query }}">
<button type="submit">Search</button>
</form>
{% if query %}
{% if results %}
<h2>Results for "{{ query }}"</h2>
<ul class="results">
{% for row in results %}
<li>
<strong>{{ row['word'] }}</strong>: {{ row['meaning'] }}
</li>
{% endfor %}
</ul>
{% else %}
<p class="no-results">No words found matching "{{ query }}".</p>
{% endif %}
{% endif %}
{% endblock %}
For app.py, confirm you have these sections in order from top to bottom:
- The import sqlite3 and from flask import ... lines at the top.
- app = Flask(__name__), app.secret_key, and DATABASE = 'dictionary.db'.
- The get_db() function.
- The close_connection() function with its @app.teardown_appcontext decorator.
- The init_db() function.
- The updated index() route with request.args.get and the database query.
- The if __name__ == '__main__': block with init_db() before app.run(debug=True).
Test the search feature
Everything is wired up. Before you test, think about what will happen when you search for a word.
The database exists but you never added any words to it. What do you think the search results page will show?
- Start the app by running:
python app.py
- Open your browser and go to http://127.0.0.1:5000.
- Type any word (for example, hello) into the search box.
- Click Search.
You see the message: "No words found matching hello." in italic text below the search form.
Why is this a success?
This message proves that everything is working correctly. Your form submitted the search term, Flask read it from the URL, queried the database, got zero results back, and your template displayed the empty-state message.
The only thing missing is actual data in the database. You have no way to add words yet. The next step solves that by building a dashboard with full create, edit, and delete controls.
Page shows an error instead of results?
If you see a NameError mentioning get_db, make sure get_db() is defined above the index() route in your file. Python reads top to bottom, so functions must be defined before they are called.
If you see a database-related error, delete dictionary.db and restart the app. A fresh run of init_db() recreates the file cleanly.
My search page shows an error instead of results
Your database and search logic work perfectly. The problem is obvious: there is no way to add words into the database yet. Next up, you will build a dashboard page with forms to add, edit, and delete vocabulary words.
Build the Dashboard with Full CRUD
Your search feature works, but every query returns "No words found" because the database is empty. There is no way to add words yet.
In this step, you will build a dashboard page that solves this problem. The dashboard gives you forms to add new vocabulary words, edit their meanings, and delete entries you no longer need.
In this step, get ready to:
- Create a dashboard template with an "Add New Word" form and a words table.
- Add routes for creating, editing, and deleting words in the database.
- Test the full loop: add a word on the dashboard, then find it with search.
Create the dashboard template and route
The dashboard needs two things: an HTML template to display the page, and a route in app.py to serve it.
- In the templates folder, create a new file called dashboard.html.
- Add the form section by pasting this code into the new file:
{% extends "base.html" %}
{% block title %}Dashboard - Dictionary Manager{% endblock %}
{% block content %}
<h1>Dashboard</h1>
<h2>Add New Word</h2>
<form method="POST" action="{{ url_for('add_word') }}">
<input type="text" name="word" placeholder="Word" required>
<input type="text" name="meaning" placeholder="Meaning" required>
<button type="submit">Add Word</button>
</form>
{% endblock %}
What does this code do?
This template extends base.html so it inherits the nav bar, flash messages, and stylesheet automatically.
- The form uses method="POST" to send data to the server when submitted.
- The required attribute on each input prevents the form from submitting if either field is empty.
- The action points to an add_word route you will create shortly.
- Save dashboard.html.
- Now switch to app.py and find the last line of the index function:
return render_template('index.html', results=results, query=query)
- Add the dashboard route below the index function by pasting this code after that line:
@app.route('/dashboard')
def dashboard():
# Query all words from the database, sorted alphabetically
db = get_db()
words = db.execute('SELECT * FROM words ORDER BY word').fetchall()
return render_template('dashboard.html', words=words)
What does this route do?
When a visitor goes to /dashboard, Flask runs this function. It fetches every word from the database sorted A to Z, then passes that list to the dashboard.html template as words.
- Save app.py.
- In your terminal, stop any running server with Ctrl+C, then start it again by running:
python app.py
- Open your browser and go to http://127.0.0.1:5000/dashboard.
You should see a heading that says "Dashboard", an "Add New Word" form with two text inputs and a button, and empty space below.
Seeing a NameError or BuildError?
If the page shows an error about add_word not being found, that is expected at this stage. The form references a route that does not exist yet. As long as the page loads and you can see the form, you are on track.
If the page does not load at all, check that your dashboard.html file is inside the templates folder and that {% extends "base.html" %} is the very first line.
Help me fix my dashboard page error.
Add the words table to the dashboard
The form is in place, but you also need a table to display all the words currently in the database.
- In dashboard.html, find the line that says {% endblock %}.
- Replace {% endblock %} with the following code (which includes the endblock at the bottom):
<h2>All Words</h2>
{% if words %}
<table>
<thead>
<tr>
<th>Word</th>
<th>Meaning</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for word in words %}
<tr>
<td>{{ word['word'] }}</td>
<td>{{ word['meaning'] }}</td>
<td>
<form method="POST" action="{{ url_for('edit_word', id=word['id']) }}" class="inline-form">
<input type="text" name="word" value="{{ word['word'] }}" required>
<input type="text" name="meaning" value="{{ word['meaning'] }}" required>
<button type="submit">Save</button>
</form>
<form method="POST" action="{{ url_for('delete_word', id=word['id']) }}" class="inline-form">
<button type="submit" class="delete-btn">Delete</button>
</form>
</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}
<p>No words in the dictionary yet. Add some above!</p>
{% endif %}
{% endblock %}
What does this table do?
The {% if words %} block checks whether the database has any entries. If it does, a table renders each word with its meaning and two action forms: one for editing (with a Save button) and one for deleting (with a red Delete button).
If the database is empty, a simple message says "No words in the dictionary yet."
- Save dashboard.html.
- Refresh http://127.0.0.1:5000/dashboard in your browser.
You should now see "No words in the dictionary yet. Add some above!" below the form.
Page not updating?
Make sure you saved dashboard.html before refreshing. Flask's debug mode auto-reloads Python files, but you still need to refresh the browser to see template changes.
Help me fix my dashboard template.
Add the CRUD routes
The dashboard template references three routes that do not exist yet: add_word, edit_word, and delete_word. Time to build them.
- In app.py, find the end of the dashboard function:
return render_template('dashboard.html', words=words)
- Add the add_word route below it by pasting this code:
@app.route('/add', methods=['POST'])
def add_word():
# Get the word and meaning from the submitted form
word = request.form['word']
meaning = request.form['meaning']
# Insert the new word into the database
db = get_db()
db.execute('INSERT INTO words (word, meaning) VALUES (?, ?)', (word, meaning))
db.commit()
flash('Word added successfully!')
return redirect(url_for('dashboard'))
What does this route do?
This route only accepts POST requests, which means it runs when the form is submitted. It reads the word and meaning values from the form data, inserts them into the database, and redirects back to the dashboard.
The flash() function stores a one-time message that the template displays as a green confirmation banner.
- Save app.py.
- Stop the server with Ctrl+C and restart it by running:
python app.py
- Go to http://127.0.0.1:5000/dashboard in your browser.
- Type python in the Word field.
- Type a programming language in the Meaning field.
- Click Add Word.
You should see a green banner saying "Word added successfully!" and the word "python" now appears in the table below.
Form submission gives an error?
If you see a "Method Not Allowed" error, check that your @app.route('/add', methods=['POST']) decorator includes methods=['POST']. Without it, Flask only allows GET requests on that URL.
Help me debug my add_word route.
- Now add the edit_word route below add_word by pasting this code:
@app.route('/edit/<int:id>', methods=['POST'])
def edit_word(id):
# Get updated values from the form
word = request.form['word']
meaning = request.form['meaning']
# Update the matching row in the database
db = get_db()
db.execute('UPDATE words SET word = ?, meaning = ? WHERE id = ?', (word, meaning, id))
db.commit()
flash('Word updated successfully!')
return redirect(url_for('dashboard'))
What is the <int:id> part?
The <int:id> in the URL is a variable rule. Flask extracts the number from the URL (like /edit/3) and passes it to the function as the id parameter. This tells the route which specific word to update.
- Add the delete_word route below edit_word by pasting this code:
@app.route('/delete/<int:id>', methods=['POST'])
def delete_word(id):
# Remove the word from the database
db = get_db()
db.execute('DELETE FROM words WHERE id = ?', (id,))
db.commit()
flash('Word deleted successfully!')
return redirect(url_for('dashboard'))
Why use POST for delete?
Deleting data is a destructive action. Using POST instead of GET prevents accidental deletion from bots or browser prefetching that might follow links automatically.
- Save app.py.
- Stop the server with Ctrl+C and restart it by running:
python app.py
- Go to http://127.0.0.1:5000/dashboard in your browser.
- In the table row for "python", change the Meaning field to a high-level programming language and click Save.
You should see a green banner saying "Word updated successfully!" and the updated meaning in the table.
- Now click the red Delete button next to the word.
The word disappears and you see "Word deleted successfully!" in the green banner.
Edit or Delete not working?
Make sure each route is a separate function and not accidentally nested inside another function. Check that @app.route('/edit/<int:id>', methods=['POST']) uses <int:id> and not <id> without the type.
Help me debug my edit and delete routes.
Before testing the full flow, think about this: if you add a word on the dashboard, will you be able to find it using the search page?
- Add a new word on the dashboard. Type flask in the Word field and a Python web framework in the Meaning field.
- Click Add Word.
- Click the Search link in the nav bar to go back to the homepage.
- Type flask in the search box and click Search.
You should see "flask: a Python web framework" in the results list. The full loop is working.
✔️ Awesome, I've got everything!
Great. Double check you have saved both app.py and dashboard.html.
ⓧ I'd like to double check the full code
Scroll up and confirm these chunks are present in your files, in order:
In app.py:
- The dashboard route (queries all words ordered by word, renders dashboard.html).
- The add_word route (POST /add, inserts into database, flashes "Word added successfully!").
- The edit_word route (POST /edit/<int:id>, updates database, flashes "Word updated successfully!").
- The delete_word route (POST /delete/<int:id>, deletes from database, flashes "Word deleted successfully!").
In templates/dashboard.html:
- Extends base.html with a title block and content block.
- An "Add New Word" form posting to add_word.
- A table that loops through words and shows inline edit and delete forms for each row.
- An {% else %} block showing "No words in the dictionary yet" when the table is empty.
Your dictionary app now has full CRUD functionality. You can create, read, update, and delete words through the browser. Next up, you will tackle a Secret Mission that makes the homepage more interesting even before the user searches.
Secret mission
Add a Word of the Day Feature
Your homepage sits empty until someone searches for something. What if it greeted visitors with a random word from the dictionary every time they loaded the page? Add a "Word of the Day" feature that picks a random entry and displays it in a highlighted box above the search form.
Clean Up Your Resources
Clean Up Your Resources
This project runs entirely locally, so there are no ongoing costs. Decide whether to keep your resources running, pause them to come back later, or delete them entirely.
Resources you used:
- The dictionary-app project folder (contains all project files, virtual environment, and SQLite database).
- Python 3.14.6 (installed on your system).
- VS Code (installed on your system).
Keep everything running
No action needed. Choose this if you're still actively building or want to keep experimenting with your dictionary app.
- Your project folder stays on your Desktop with all files intact.
- You can restart the app anytime by activating the virtual environment and running python app.py.
- Python and VS Code remain installed for future projects.
Pause - I'll come back to this later
Stop the running Flask server to free up your terminal. Your files stay on disk so you can pick up where you left off.
- If the Flask dev server is still running in your terminal, press Ctrl+C to stop it.
- Deactivate the virtual environment by running:
deactivate
- To resume later, open VS Code, open the terminal, navigate to your dictionary-app folder, run venv\Scripts\activate, then run python app.py.
Delete - I don't want to use this again
Remove all project files and optionally uninstall the tools you set up.
- If the Flask server is still running, press Ctrl+C to stop it.
- Deactivate the virtual environment by running:
deactivate
- Navigate to the parent folder and delete the project folder by running:
cd ~/Desktop
rmdir /s /q dictionary-app
- To uninstall Python: press the Windows key, type Add or remove programs, press Enter. Find Python 3.14.6 in the list, click it, then click Uninstall.
- To uninstall VS Code: in the same Add or remove programs window, find Microsoft Visual Studio Code, click it, then click Uninstall.
Nice Work!
Nice Work!
Nice work! You just built a fully functional Dictionary Manager web application from scratch using Flask, SQLite, and Jinja2 templates.
You've learned how to:
- Built a complete Flask web application from scratch with a single Python file (app.py) containing all routes.
- Created a SQLite database and performed full CRUD operations (Create, Read, Update, Delete) through HTML forms.
- Used Jinja2 template inheritance to share a common layout (base.html) across multiple pages and built forms that submit data using GET and POST methods.
- Secret Mission: Added a dynamic Word of the Day feature using Python's random module to display a random word from the database on the homepage.
Ready to quiz yourself?