Ad – 728Γ—90
🌐 Projects

Python Full-Stack Project – Flask Blog

Build a complete blog web application with Flask: user registration, login, post CRUD, SQLite storage, and Jinja2 templates.

⏱️ 20 min read🎯 ProjectsπŸ“… Updated 2026

Setup

Bash
pip install flask flask-sqlalchemy flask-login werkzeug

models.py

Python
from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin
from datetime import datetime
from werkzeug.security import generate_password_hash, check_password_hash

db = SQLAlchemy()

class User(UserMixin, db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False)
    email = db.Column(db.String(120), unique=True, nullable=False)
    password_hash = db.Column(db.String(256))
    posts = db.relationship("Post", backref="author", lazy=True)
    def set_password(self, p): self.password_hash = generate_password_hash(p)
    def check_password(self, p): return check_password_hash(self.password_hash, p)

class Post(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    title = db.Column(db.String(200), nullable=False)
    content = db.Column(db.Text, nullable=False)
    created_at = db.Column(db.DateTime, default=datetime.utcnow)
    user_id = db.Column(db.Integer, db.ForeignKey("user.id"), nullable=False)

app.py

Python
from flask import Flask, render_template, redirect, url_for, request, flash
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from models import db, User, Post

app = Flask(__name__)
app.config["SECRET_KEY"] = "change-in-production"
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///blog.db"
db.init_app(app)
login_manager = LoginManager(app)
login_manager.login_view = "login"

@login_manager.user_loader
def load_user(uid): return User.query.get(int(uid))

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

@app.route("/new", methods=["GET", "POST"])
@login_required
def new_post():
    if request.method == "POST":
        post = Post(title=request.form["title"], content=request.form["content"], author=current_user)
        db.session.add(post); db.session.commit()
        return redirect(url_for("index"))
    return render_template("new_post.html")

@app.route("/register", methods=["GET", "POST"])
def register():
    if request.method == "POST":
        user = User(username=request.form["username"], email=request.form["email"])
        user.set_password(request.form["password"])
        db.session.add(user); db.session.commit()
        login_user(user); return redirect(url_for("index"))
    return render_template("register.html")

@app.route("/login", methods=["GET", "POST"])
def login():
    if request.method == "POST":
        user = User.query.filter_by(email=request.form["email"]).first()
        if user and user.check_password(request.form["password"]):
            login_user(user); return redirect(url_for("index"))
        flash("Invalid credentials")
    return render_template("login.html")

@app.route("/logout")
@login_required
def logout(): logout_user(); return redirect(url_for("index"))

with app.app_context(): db.create_all()
if __name__ == "__main__": app.run(debug=True)
Bash
python app.py
# http://localhost:5000
Tip: For production: Gunicorn as WSGI server, Nginx as reverse proxy. Never run Flask dev server in production.