One of the best ways to get job-ready with Python is by building small, functional apps. In this guide, we’ll create a Notes App where you can:
- Create new notes
- Read all saved notes
- Update existing notes
- Delete notes
And unlike an in-memory app, this one will use SQLite so your notes are stored in a database and won’t disappear when you restart the server.
1. Why Flask + SQLite?
- Flask → A lightweight Python web framework. Perfect for learning and small apps.
- SQLite → A file-based database that comes built into Python (
sqlite3
). No extra installation needed.
This combo is ideal when you’re just starting with web development.
2. Project Setup
Create a folder structure like this:
crud_app/
│
├── app.py # main Flask app
├── templates/
│ ├── base.html
│ ├── index.html
│ ├── edit.html
👉 Flask automatically looks inside templates/
for HTML files.
3. Installing Flask
Run this in your terminal:
pip install flask
4. The Flask App (app.py
)
import sqlite3
from flask import Flask, render_template, request, redirect
app = Flask(__name__)
# Connect to SQLite
def get_db_connection():
conn = sqlite3.connect('notes.db')
conn.row_factory = sqlite3.Row # lets us access rows as dict-like objects
return conn
# Initialize DB with a notes table
def init_db():
conn = get_db_connection()
conn.execute('''
CREATE TABLE IF NOT EXISTS notes (
id INTEGER PRIMARY KEY AUTOINCREMENT,
content TEXT NOT NULL
)
''')
conn.commit()
conn.close()
init_db()
# READ: Show all notes
@app.route('/')
def index():
conn = get_db_connection()
notes = conn.execute('SELECT * FROM notes').fetchall()
conn.close()
return render_template('index.html', notes=notes)
# CREATE: Add a new note
@app.route('/add', methods=['POST'])
def add_note():
note = request.form.get('note')
if note:
conn = get_db_connection()
conn.execute('INSERT INTO notes (content) VALUES (?)', (note,))
conn.commit()
conn.close()
return redirect('/')
# UPDATE: Edit an existing note
@app.route('/edit/<int:id>', methods=['GET', 'POST'])
def edit(id):
conn = get_db_connection()
note = conn.execute('SELECT * FROM notes WHERE id = ?', (id,)).fetchone()
if request.method == 'POST':
new_content = request.form.get('note')
conn.execute('UPDATE notes SET content = ? WHERE id = ?', (new_content, id))
conn.commit()
conn.close()
return redirect('/')
conn.close()
return render_template('edit.html', note=note)
# DELETE: Remove a note
@app.route('/delete/<int:id>')
def delete(id):
conn = get_db_connection()
conn.execute('DELETE FROM notes WHERE id = ?', (id,))
conn.commit()
conn.close()
return redirect('/')
if __name__ == "__main__":
app.run(debug=True)
What’s happening here:
get_db_connection()
→ opens a connection tonotes.db
.init_db()
→ makes sure thenotes
table exists./
(GET) → fetches all notes and shows them./add
(POST) → adds a new note./edit/<id>
→ lets you edit a note./delete/<id>
→ removes a note.
5. Templates
templates/base.html
A base layout so you don’t repeat boilerplate.
<!doctype html>
<html>
<head>
<title>Simple Notes App</title>
</head>
<body>
<h1>My Notes</h1>
{% block content %}{% endblock %}
</body>
</html>
templates/index.html
Shows the form and the list of notes.
{% extends 'base.html' %}
{% block content %}
<form method="post" action="/add">
<input type="text" name="note" placeholder="Write a note">
<button type="submit">Add</button>
</form>
<ul>
{% for note in notes %}
<li>
{{ note.content }}
<a href="/edit/{{ note.id }}">Edit</a>
<a href="/delete/{{ note.id }}">Delete</a>
</li>
{% endfor %}
</ul>
{% endblock %}
templates/edit.html
Form for editing a note.
{% extends 'base.html' %}
{% block content %}
<form method="post">
<input type="text" name="note" value="{{ note.content }}">
<button type="submit">Update</button>
</form>
{% endblock %}
6. Running the App
Run:
python app.py
Visit http://127.0.0.1:5000 in your browser. Now your notes are saved in notes.db
.