The database system uses PostgreSQL as the primary database with SQLAlchemy ORM for database operations. It includes migrations via Flask-Migrate and supports all forum data including users, posts, comments, votes, and more.
DATABASE_URL: PostgreSQL connection stringpostgresql://user:password@host:port/databasepostgresql://forumuser:password@localhost:5432/forumdbpython
app.config['SQLALCHEMY_DATABASE_URI'] = os.environ.get('DATABASE_URL')
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
username VARCHAR(64) UNIQUE NOT NULL,
email VARCHAR(120) UNIQUE NOT NULL,
password_hash VARCHAR(256) NOT NULL,
is_admin BOOLEAN DEFAULT FALSE,
is_verified BOOLEAN DEFAULT FALSE,
verification_token VARCHAR(256),
reset_token VARCHAR(256),
reset_token_expiration TIMESTAMP,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);CREATE INDEX idx_users_username ON users(username);
CREATE INDEX idx_users_email ON users(email);
sql
CREATE TABLE repositories (
id SERIAL PRIMARY KEY,
name VARCHAR(128) NOT NULL,
description TEXT,
github_url VARCHAR(256) UNIQUE NOT NULL,
stars INTEGER DEFAULT 0,
language VARCHAR(64),
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);CREATE INDEX idx_repositories_github_url ON repositories(github_url);
sql
CREATE TABLE categories (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE NOT NULL,
description TEXT,
color VARCHAR(7) DEFAULT '#00f5ff'
);
sql
CREATE TABLE posts (
id SERIAL PRIMARY KEY,
title VARCHAR(256) NOT NULL,
content TEXT NOT NULL,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
repository_id INTEGER REFERENCES repositories(id) ON DELETE SET NULL,
category_id INTEGER REFERENCES categories(id) ON DELETE SET NULL,
attachment VARCHAR(256),
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
upvotes INTEGER DEFAULT 0,
downvotes INTEGER DEFAULT 0
);CREATE INDEX idx_posts_user_id ON posts(user_id);
CREATE INDEX idx_posts_created_at ON posts(created_at DESC);
CREATE INDEX idx_posts_category_id ON posts(category_id);
sql
CREATE TABLE comments (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
post_id INTEGER NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
upvotes INTEGER DEFAULT 0,
downvotes INTEGER DEFAULT 0
);CREATE INDEX idx_comments_post_id ON comments(post_id);
CREATE INDEX idx_comments_created_at ON comments(created_at DESC);
sql
CREATE TABLE votes (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
post_id INTEGER REFERENCES posts(id) ON DELETE CASCADE,
comment_id INTEGER REFERENCES comments(id) ON DELETE CASCADE,
value INTEGER NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
CHECK (value IN (1, -1))
);CREATE UNIQUE INDEX idx_votes_user_post ON votes(user_id, post_id) WHERE post_id IS NOT NULL;
CREATE UNIQUE INDEX idx_votes_user_comment ON votes(user_id, comment_id) WHERE comment_id IS NOT NULL;
sql
CREATE TABLE notifications (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
content TEXT NOT NULL,
link VARCHAR(256),
is_read BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);CREATE INDEX idx_notifications_user_id ON notifications(user_id);
CREATE INDEX idx_notifications_is_read ON notifications(is_read);
sql
CREATE TABLE messages (
id SERIAL PRIMARY KEY,
sender_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
receiver_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
content TEXT NOT NULL,
is_read BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);CREATE INDEX idx_messages_sender_id ON messages(sender_id);
CREATE INDEX idx_messages_receiver_id ON messages(receiver_id);
CREATE INDEX idx_messages_is_read ON messages(is_read);
sql
CREATE TABLE bookmarks (
id SERIAL PRIMARY KEY,
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
post_id INTEGER NOT NULL REFERENCES posts(id) ON DELETE CASCADE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
UNIQUE (user_id, post_id)
);CREATE INDEX idx_bookmarks_user_id ON bookmarks(user_id);
sql
CREATE TABLE badges (
id SERIAL PRIMARY KEY,
name VARCHAR(64) UNIQUE NOT NULL,
description TEXT,
icon VARCHAR(32) DEFAULT '★',
color VARCHAR(7) DEFAULT '#ff00ff'
);
sql
CREATE TABLE user_badges (
user_id INTEGER NOT NULL REFERENCES users(id) ON DELETE CASCADE,
badge_id INTEGER NOT NULL REFERENCES badges(id) ON DELETE CASCADE,
PRIMARY KEY (user_id, badge_id)
);
bash
Generate migration
flask db migrate -m "description"Apply migrations
flask db upgradeRollback migration
flask db downgradeView migration history
flask db history
python
Creates admin user
Creates default categories
Initializes database
Run after first migration
bash
python init_db.py
Get User by Username
python
user = User.query.filter_by(username='username').first()
Get Posts with Category
python
posts = Post.query.filter_by(category_id=category_id).all()
Get Unread Notifications
python
notifications = Notification.query.filter_by(user_id=user.id, is_read=False).all()
Search Posts
python
posts = Post.query.filter(
(Post.title.ilike(f'%{query}%')) |
(Post.content.ilike(f'%{query}%'))
).all()
bash
Full backup
pg_dump -U username -d forumdb > backup.sqlRestore
psql -U username -d forumdb < backup.sql
bash
Vacuum and analyze
VACUUM ANALYZE;Reindex
REINDEX DATABASE forumdb;Update statistics
ANALYZE;