Python Blog Website Project

Python project 09

Python Blog Website Project

Last updated: 31 August 2026

Build a minimal local blog website with Flask and SQLite. It lets you create posts, view a feed, and open an individual post page—an excellent introduction to routes, forms, templates, and databases.

Create web apps with PythonView all project ideas

What you will build

The app runs locally and creates a SQLite database automatically. Users can write posts, browse all posts, and open one post by its ID.

Skills practised

  • Flask routes and forms
  • SQLite database basics
  • Templates and redirects
  • Local web development

Requirements

  • Python 3.8 or later
  • Flask: pip install flask
  • A terminal and web browser
  • About 45 minutes to build

Full Python code

Save it as blog_website.py, then run it from a terminal.

"""A minimal Flask blog website with SQLite storage for learning purposes."""

import sqlite3
from pathlib import Path

from flask import Flask, abort, redirect, render_template_string, request, url_for

app = Flask(__name__)
DATABASE = Path("blog.db")

PAGE_TEMPLATE = """
<!doctype html><title>Mini Python Blog</title>
<style>body{font-family:system-ui;max-width:760px;margin:40px auto;padding:0 18px}input,textarea{width:100%;margin:6px 0 14px;padding:9px}article{border-bottom:1px solid #ddd;padding:14px 0}</style>
<h1>Mini Python Blog</h1><p><a href="{{ url_for('new_post') }}">Write a post</a></p>
{% for post in posts %}<article><h2><a href="{{ url_for('post_detail', post_id=post['id']) }}">{{ post['title'] }}</a></h2><p>{{ post['body'][:180] }}{% if post['body']|length > 180 %}...{% endif %}</p></article>{% else %}<p>No posts yet. Write the first one.</p>{% endfor %}
"""
FORM_TEMPLATE = """<!doctype html><title>Write a post</title><h1>Write a post</h1><form method="post"><label>Title</label><input name="title" required maxlength="120"><label>Body</label><textarea name="body" required rows="10"></textarea><button>Publish</button></form><p><a href="{{ url_for('index') }}">Back to posts</a></p>"""
POST_TEMPLATE = """<!doctype html><title>{{ post['title'] }}</title><main><h1>{{ post['title'] }}</h1><p>{{ post['body'] }}</p><a href="{{ url_for('index') }}">Back to posts</a></main>"""


def connection():
    database = sqlite3.connect(DATABASE)
    database.row_factory = sqlite3.Row
    return database


def setup_database():
    with connection() as database:
        database.execute("CREATE TABLE IF NOT EXISTS posts (id INTEGER PRIMARY KEY, title TEXT NOT NULL, body TEXT NOT NULL)")


@app.route("/")
def index():
    with connection() as database:
        posts = database.execute("SELECT id, title, body FROM posts ORDER BY id DESC").fetchall()
    return render_template_string(PAGE_TEMPLATE, posts=posts)


@app.route("/new", methods=["GET", "POST"])
def new_post():
    if request.method == "POST":
        with connection() as database:
            database.execute("INSERT INTO posts (title, body) VALUES (?, ?)", (request.form["title"].strip(), request.form["body"].strip()))
        return redirect(url_for("index"))
    return render_template_string(FORM_TEMPLATE)


@app.route("/post/<int:post_id>")
def post_detail(post_id):
    with connection() as database:
        post = database.execute("SELECT id, title, body FROM posts WHERE id = ?", (post_id,)).fetchone()
    if post is None:
        abort(404)
    return render_template_string(POST_TEMPLATE, post=post)


if __name__ == "__main__":
    setup_database()
    app.run(debug=True)

How it works

setup_database() creates the posts table. Each route has one purpose: list posts, display the creation form, save a post, or display one post. Parameterized SQL values prevent unsafe string-building in the database query.

Run the project

  1. Install Flask with pip install flask.
  2. Run python blog_website.py.
  3. Open http://127.0.0.1:5000/ in a browser.
  4. Write a post and open it from the home page.

Notes for your notebook

  • Development server: use it only on your own computer while learning.
  • Production: needs secure configuration, authentication, and a production WSGI server.
  • Database: SQLite is a strong starting point for small local projects.

Ways to extend it

Add post dates, Markdown support, editing and deletion, login protection, image uploads, and a production deployment after learning Flask security basics.

What to learn next

Strengthen your foundations through Python functions and choose another task from the Softenant project library.