Python Flask Blog Application Tutorial

Written by

in

Welcome to the ultimate Python Flask blog application tutorial! Whether you’re a seasoned developer looking to add a personal blog to your portfolio or a beginner eager to see a real‑world Flask project in action, this guide walks you through every step—from setting up your environment to deploying a SEO‑friendly blog that scales. By the end of this article, you’ll have a fully functional Flask blog, complete with CRUD (Create, Read, Update, Delete) operations, a SQLite database, and a responsive design powered by Bootstrap.

Why Choose Flask for a Blog?

Flask is a lightweight, micro‑framework that gives you the flexibility to build exactly what you need without the bloat of larger frameworks. Here are a few reasons Flask shines for blogging platforms:

  • Simple routing: Define URLs with just a decorator.
  • Extensible: Add extensions like Flask‑SQLAlchemy or Flask‑Login as your project grows.
  • Great for SEO: Full control over HTML markup, meta tags, and URL structure.
  • Pythonic: Leverage Python’s readability and vast ecosystem.

Prerequisites

Before diving in, make sure you have the following tools installed on your machine:

  1. Python 3.9 or newer
  2. pip (Python package manager)
  3. Virtualenv (optional but recommended)
  4. A code editor (VS Code, PyCharm, etc.)
  5. Basic knowledge of HTML, CSS, and Python

Setting Up the Development Environment

1. Create a Virtual Environment

python -m venv venv
source venv/bin/activate  # On Windows use: venv\Scripts\activate

2. Install Flask and Required Extensions

pip install Flask Flask‑SQLAlchemy Flask‑Migrate Flask‑Bootstrap

3. Define Your Project Structure

A clean folder layout makes the code easier to maintain and scale:

flask_blog/
│
├── app/
│   ├── __init__.py
│   ├── models.py
│   ├── routes.py
│   ├── templates/
│   │   ├── base.html
│   │   ├── index.html
│   │   └── post.html
│   └── static/
│       └── css/
│           └── style.css
│
├── migrations/
├── config.py
└── run.py

Creating the Flask Application

Initialize the App

Open app/__init__.py and set up the core Flask instance along with the database:

from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
from flask_bootstrap import Bootstrap

db = SQLAlchemy()
migrate = Migrate()

def create_app():
    app = Flask(__name__)
    app.config.from_object('config.Config')

    db.init_app(app)
    migrate.init_app(app, db)
    Bootstrap(app)

    with app.app_context():
        from . import routes, models
        db.create_all()

    return app

Configuration File

Store sensitive settings in config.py:

import os

class Config:
    SECRET_KEY = os.getenv('SECRET_KEY', 'dev_key')
    SQLALCHEMY_DATABASE_URI = os.getenv('DATABASE_URL',
        'sqlite:///blog.db')
    SQLALCHEMY_TRACK_MODIFICATIONS = False

Defining the Data Model

In app/models.py create a simple Post model to store blog entries:

from . import db
from datetime import datetime

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(150), nullable=False)
    slug = db.Column(db.String(150), unique=True, nullable=False)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)

    def __repr__(self):
        return f"<Post {self.title}>"

Building Routes and Templates

Home Page – List of Posts

from flask import render_template, request, redirect, url_for, flash
from . import app, db
from .models import Post
from slugify import slugify

@app.route('/')
def index():
    posts = Post.query.order_by(Post.created_at.desc()).all()
    return render_template('index.html', posts=posts)

Sample templates/index.html using Bootstrap cards:

<{% extends "base.html" %}>
<{% block content %}>
<h2 class="mt-4">Latest Posts</h2>
<div class="row">
    {% for post in posts %}
    <div class="col-md-6 mb-4">
        <div class="card">
            <div class="card-body">
                <h5 class="card-title">{{ post.title }}</h5>
                <p class="card-text">{{ post.content[:150] }}...</p>
                <a href="{{ url_for('post_detail', slug=post.slug) }}" class="btn btn-primary">Read More</a>
            </div>
        </div>
    </div>
    {% endfor %}
</div>
<{% endblock %}>

Post Detail Page

@app.route('/post/<slug>')
def post_detail(slug):
    post = Post.query.filter_by(slug=slug).first_or_404()
    return render_template('post.html', post=post)

Implementing CRUD Operations

Create a New Post

@app.route('/admin/create', methods=['GET', 'POST'])
def create_post():
    if request.method == 'POST':
        title = request.form['title']
        content = request.form['content']
        slug = slugify(title)
        new_post = Post(title=title, content=content, slug=slug)
        db.session.add(new_post)
        db.session.commit()
        flash('Post created successfully!', 'success')
        return redirect(url_for('index'))
    return render_template('create.html')

Edit an Existing Post

@app.route('/admin/edit/<int:id>', methods=['GET', 'POST'])
def edit_post(id):
    post = Post.query.get_or_404(id)
    if request.method == 'POST':
        post.title = request.form['title']
        post.content = request.form['content']
        post.slug = slugify(post.title)
        db.session.commit()
        flash('Post updated!', 'info')
        return redirect(url_for('post_detail', slug=post.slug))
    return render_template('edit.html', post=post)

Delete a Post

@app.route('/admin/delete/<int:id>', methods=['POST'])
def delete_post(id):
    post = Post.query.get_or_404(id)
    db.session.delete(post)
    db.session.commit()
    flash('Post removed.', 'warning')
    return redirect(url_for('index'))

Styling the Blog with Bootstrap

Flask‑Bootstrap automatically injects the latest Bootstrap CSS/JS. In templates/base.html you can add custom meta tags for SEO and a simple navigation bar:

<

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *