Concepts 🚀 Project 🧮 Labs
📚 Learn / Mini Projects / SQLite + SQLAlchemy from Scratch

SQLite + SQLAlchemy from Scratch

Set up a SQLite database, define models, run queries, run migrations. The data layer behind every backend.

🚀 Mini Project · 3 files

Project files

📄 models.py python
from sqlalchemy import Column, Integer, String, Float, DateTime, ForeignKey, create_engine
from sqlalchemy.orm import declarative_base, relationship
from datetime import datetime

Base = declarative_base()

class Author(Base):
    __tablename__ = 'authors'
    id = Column(Integer, primary_key=True)
    name = Column(String, unique=True, nullable=False)
    email = Column(String)
    posts = relationship('Post', back_populates='author')

class Post(Base):
    __tablename__ = 'posts'
    id = Column(Integer, primary_key=True)
    title = Column(String, nullable=False)
    body = Column(String)
    rating = Column(Float, default=0.0)
    created_at = Column(DateTime, default=datetime.utcnow)
    author_id = Column(Integer, ForeignKey('authors.id'))
    author = relationship('Author', back_populates='posts')

engine = create_engine('sqlite:///blog.db', echo=True)
Base.metadata.create_all(engine)
📄 queries.py python
from sqlalchemy.orm import sessionmaker
from models import engine, Author, Post

Session = sessionmaker(bind=engine)
session = Session()

# Create
ada = Author(name='Ada', email='ada@x.com')
session.add(ada)
session.commit()  # writes to DB, ada.id is now set

post1 = Post(title='Hello', body='First post', author=ada)
post2 = Post(title='World', body='Second post', rating=4.5, author=ada)
session.add_all([post1, post2])
session.commit()

# Read
all_posts = session.query(Post).all()
print('all posts:', [p.title for p in all_posts])

# Filter
top = session.query(Post).filter(Post.rating >= 4).all()
print('top rated:', [p.title for p in top])

# Order + limit
recent = (session.query(Post)
          .order_by(Post.created_at.desc())
          .limit(5).all())

# Join via relationship
ada_posts = session.query(Author).filter_by(name='Ada').first().posts
print('ada posts:', [p.title for p in ada_posts])

# Update
post1.rating = 5.0
session.commit()

# Delete
session.delete(post2)
session.commit()

session.close()
📄 run.sh bash
pip install sqlalchemy

# Create tables
python models.py

# Run CRUD operations
python queries.py
# SQL queries are echoed to stdout (echo=True)

# Inspect the DB
sqlite3 blog.db
# sqlite> .tables
# authors  posts
# sqlite> SELECT * FROM authors;
# 1|Ada|ada@x.com

How it works

SQLAlchemy is the Python ORM — you write Python classes, it generates SQL. The flow: (1) models.py defines Author and Post classes. Each Column(...) maps to a DB column. primary_key=True marks the id. ForeignKey('authors.id') creates a one-to-many relationship (one author, many posts). relationship('Post', back_populates='author') lets you do ada.posts and post.author — SQLAlchemy runs the JOIN under the hood. (2) create_engine('sqlite:///blog.db') connects to a local SQLite file. echo=True prints every SQL query — great for learning. (3) Base.metadata.create_all(engine) inspects the models and runs CREATE TABLE. (4) queries.py shows the 4 CRUD patterns: create (add + commit), read (query.all / query.filter), update (mutate attribute + commit), delete (session.delete + commit). The session is a unit of work — changes are tracked in memory until commit() flushes them to the DB.

⚡ Open in Notebook
🔍 Where this is used in OpenBenchML app/database/models.py defines User, Model, Dataset, BenchmarkJob, LeaderboardEntry, Competition, Comment. app/database/db.py creates the engine + session factory.