π Building a Mini Blog with Flask + SQLite
After learning basic Python syntax and building simple console apps, I wanted to step into real web development using Flask. This project is a minimal blog system where you can write posts, save them into a database, and display them on a clean UI.
Unlike the earlier projects, this one required thinking more about structure β backend logic, routes, HTML templates, and how data flows between each layer. It was definitely more challenging, but I learned a lot through the process. I hope this project helps anyone who wants to start Flask or backend development.
π 1. Project Structure
flask_blog/
βββ app.py # Flask server
βββ blog.db # SQLite DB (auto-created)
βββ templates/
βββ index.html # Show all posts
βββ new.html # Create new post
π§ 2. How It Works
- Flask handles routes: home, new post page, create post
- SQLite stores blog posts
- Templates render posts using Jinja2
- Posts are listed in reverse chronological order
π₯οΈ 3. Main App (app.py)
from flask import Flask, render_template, request, redirect
import sqlite3
# Initialize the Flask application
app = Flask(__name__)
# ---------- Database Initialization Function ----------
def init_db():
conn = sqlite3.connect("blog.db")
cur = conn.cursor()
cur.execute("""
CREATE TABLE IF NOT EXISTS posts (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
content TEXT NOT NULL
)
""")
conn.commit()
conn.close()
# Run DB init on app start
init_db()
# ---------- Home Route ----------
@app.route("/")
def index():
conn = sqlite3.connect("blog.db")
cur = conn.cursor()
cur.execute("SELECT id, title, content FROM posts ORDER BY id DESC")
posts = cur.fetchall()
conn.close()
return render_template("index.html", posts=posts)
# ---------- New Post Page ----------
@app.route("/new")
def new_post():
return render_template("new.html")
# ---------- Post Creation ----------
@app.route("/create", methods=["POST"])
def create_post():
title = request.form["title"]
content = request.form["content"]
conn = sqlite3.connect("blog.db")
cur = conn.cursor()
cur.execute(
"INSERT INTO posts (title, content) VALUES (?, ?)",
(title, content)
)
conn.commit()
conn.close()
return redirect("/")
if __name__ == "__main__":
app.run(debug=True)
πΌοΈ 4. Templates
π index.html β Display All Posts
<!DOCTYPE html>
<html>
<head>
<title>Mini Blog</title>
<style>
body { font-family: sans-serif; padding: 20px; background-color: #f4f7f9; }
.post {
border: 1px solid #ddd;
padding: 15px;
margin-bottom: 15px;
border-radius: 8px;
background-color: white;
box-shadow: 0 2px 4px rgba(0,0,0,0.05);
}
.post h3 { color: #333; margin-top: 0; }
.top {
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 2px solid #007bff;
margin-bottom: 20px;
padding-bottom: 10px;
}
.top h1 { margin: 0; }
a { text-decoration: none; color: #007bff; font-weight: bold; }
a:hover { text-decoration: underline; color: #0056b3; }
</style>
</head>
<body>
<div class="top">
<h1>Mini Blog Posts</h1>
<a href="/new">Write New Post →</a>
</div>
{% for post in posts %}
<div class="post">
<h3>{{ post[1] }}</h3>
<p>{{ post[2] }}</p>
</div>
{% endfor %}
{% if not posts %}
<p style="color: #6c757d;">No posts yet. Start writing your first entry!</p>
{% endif %}
</body>
</html>
π new.html β Create a New Post
<!DOCTYPE html>
<html>
<head>
<title>Create New Post</title>
<style>
body { font-family: sans-serif; padding: 20px; background-color: #f4f7f9; }
h1 { color: #333; border-bottom: 2px solid #007bff; padding-bottom: 10px; margin-bottom: 20px; }
form {
display: flex;
flex-direction: column;
gap: 15px;
width: 90%;
max-width: 600px;
background-color: white;
padding: 20px;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0,0,0,0.1);
}
input, textarea {
padding: 12px;
border: 1px solid #ccc;
border-radius: 6px;
font-size: 16px;
}
textarea { resize: vertical; }
button {
padding: 12px;
background: #28a745;
color: #fff;
border: none;
border-radius: 6px;
font-size: 18px;
cursor: pointer;
transition: background 0.3s;
}
button:hover { background: #1e7e34; }
.back-link { margin-top: 20px; display: block; color: #6c757d; text-decoration: none; }
</style>
</head>
<body>
<h1>Create New Post</h1>
<form action="/create" method="POST">
<input type="text" name="title" placeholder="Post Title" required>
<textarea name="content" rows="10" placeholder="Post Content" required></textarea>
<button type="submit">Save Post</button>
</form>
<a href="/" class="back-link">← Back to Home</a>
</body>
</html>
π 5. What I Learned
- Building a full CRUD workflow (Create + Read)
- Working with Flask routes, request handling, and redirects
- Rendering templates using Jinja2
- Designing clean UI with HTML + CSS
- Saving data relationally using SQLite
π§ 6. Try It Yourself β Easy Improvements
If you're new to Flask and want to practice a little more, here are some simple improvements you can try. Each task is beginner-friendly and will help you understand the project more deeply.
- Add a delete button β let users remove a post they donβt need anymore.
- Add timestamps β save the date when a post is created and show it under the title.
- Clear form after submitting β reset the text fields once a post is saved.
- Improve the design β change colors, spacing, or fonts to make the blog look nicer.
-
Separate the CSS β create a small
style.cssfile instead of keeping the CSS in the HTML.
These are small changes, but each one helps you understand how Flask works step by step. Try one at a time β youβll be surprised how much you can learn from even tiny improvements!
Top comments (0)