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‑SQLAlchemyorFlask‑Loginas 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:
- Python 3.9 or newer
- pip (Python package manager)
- Virtualenv (optional but recommended)
- A code editor (VS Code, PyCharm, etc.)
- 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:
<
Leave a Reply