π Flask Database Relationships & Migrations
Building a Family Tree for Your Data
Imagine your database is like a big family album. Each photo (table) shows different people (data), but what makes it interesting is how everyone is connected β who is whose parent, sibling, or friend.
In Flask, we use SQLAlchemy to create these family connections. Letβs learn how!
π― What Weβll Learn
graph LR A["Database Relationships"] --> B["One-to-Many"] A --> C["Many-to-Many"] A --> D["One-to-One"] A --> E["Foreign Keys"] A --> F["Backref & back_populates"] G["Migrations"] --> H["Flask-Migrate Setup"] G --> I["Migration Operations"]
π Foreign Keys: The Connection Thread
What is a Foreign Key?
Think of a foreign key like a name tag that says βI belong to this family.β
When you write your name on your lunchbox, everyone knows itβs yours. A foreign key does the same thing β it tells one table βthis record belongs to that record over there.β
Simple Example
class Author(db.Model):
id = db.Column(db.Integer,
primary_key=True)
name = db.Column(db.String(100))
class Book(db.Model):
id = db.Column(db.Integer,
primary_key=True)
title = db.Column(db.String(200))
# Foreign key points to Author
author_id = db.Column(
db.Integer,
db.ForeignKey('author.id')
)
π Key Point: author_id is the name tag that connects each book to its author.
π¨βπ§βπ¦ One-to-Many Relationships
The Story
Imagine a teacher with many students. One teacher β Many students. But each student has only one teacher (in that class).
This is One-to-Many β the most common relationship!
Real-World Examples
- π« One School β Many Students
- π One Author β Many Books
- π One Customer β Many Orders
Code Example
class Teacher(db.Model):
id = db.Column(db.Integer,
primary_key=True)
name = db.Column(db.String(100))
# One teacher has MANY students
students = db.relationship(
'Student',
backref='teacher'
)
class Student(db.Model):
id = db.Column(db.Integer,
primary_key=True)
name = db.Column(db.String(100))
# Foreign key links to teacher
teacher_id = db.Column(
db.Integer,
db.ForeignKey('teacher.id')
)
How to Use It
# Get all students of a teacher
teacher = Teacher.query.first()
print(teacher.students) # List!
# Get a student's teacher
student = Student.query.first()
print(student.teacher) # One teacher
π― Many-to-Many Relationships
The Story
Think about students and clubs. One student can join many clubs. And one club has many students.
This is like a web of friendships β everyone connected to everyone!
The Secret: Association Table
We need a βhelper tableβ that keeps track of who belongs to what.
# Helper table (no class needed!)
student_clubs = db.Table(
'student_clubs',
db.Column('student_id', db.Integer,
db.ForeignKey('student.id')),
db.Column('club_id', db.Integer,
db.ForeignKey('club.id'))
)
class Student(db.Model):
id = db.Column(db.Integer,
primary_key=True)
name = db.Column(db.String(100))
# Many-to-many relationship
clubs = db.relationship(
'Club',
secondary=student_clubs,
backref='members'
)
class Club(db.Model):
id = db.Column(db.Integer,
primary_key=True)
name = db.Column(db.String(100))
How to Use It
# Add student to club
chess_club.members.append(alice)
# Get all clubs a student joined
print(alice.clubs)
# Get all members in a club
print(chess_club.members)
π One-to-One Relationships
The Story
Think of a person and their passport. Each person has exactly one passport. And each passport belongs to exactly one person.
Code Example
class Person(db.Model):
id = db.Column(db.Integer,
primary_key=True)
name = db.Column(db.String(100))
# One-to-one: uselist=False
passport = db.relationship(
'Passport',
backref='owner',
uselist=False # Key!
)
class Passport(db.Model):
id = db.Column(db.Integer,
primary_key=True)
number = db.Column(db.String(20))
person_id = db.Column(
db.Integer,
db.ForeignKey('person.id'),
unique=True # Only one!
)
π Magic Trick: uselist=False tells Flask βgive me ONE object, not a list.β
π Backref vs back_populates
The Quick Choice
| Feature | backref |
back_populates |
|---|---|---|
| Lines of code | Less | More |
| Clarity | Magic | Explicit |
| Best for | Simple cases | Complex cases |
backref (The Shortcut)
class Parent(db.Model):
id = db.Column(db.Integer,
primary_key=True)
children = db.relationship(
'Child',
backref='parent' # Auto-magic!
)
class Child(db.Model):
id = db.Column(db.Integer,
primary_key=True)
parent_id = db.Column(
db.Integer,
db.ForeignKey('parent.id')
)
# child.parent works automatically!
back_populates (The Clear Way)
class Parent(db.Model):
id = db.Column(db.Integer,
primary_key=True)
children = db.relationship(
'Child',
back_populates='parent'
)
class Child(db.Model):
id = db.Column(db.Integer,
primary_key=True)
parent_id = db.Column(
db.Integer,
db.ForeignKey('parent.id')
)
# Explicit declaration
parent = db.relationship(
'Parent',
back_populates='children'
)
π When to use which?
backref: Quick projects, simple modelsback_populates: Large projects, need clarity
π Flask-Migrate Setup
Why Migrations?
Imagine you built a LEGO castle. Now you want to add a tower. You donβt destroy the whole castle β you just add pieces.
Migrations let you change your database structure without losing data!
Step 1: Install
pip install Flask-Migrate
Step 2: Setup in Your App
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = \
'sqlite:///myapp.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db) # Add this!
Step 3: Initialize
flask db init
This creates a migrations folder β your database diary!
π Database Migration Operations
The Three Magic Commands
graph TD A["Change Model"] --> B["flask db migrate"] B --> C["flask db upgrade"] D["Want to undo?"] --> E["flask db downgrade"]
1. Create Migration
After changing your models:
flask db migrate -m "Add user table"
This creates a recipe file describing changes.
2. Apply Changes
flask db upgrade
This actually updates your database!
3. Undo Changes
Made a mistake? Go back:
flask db downgrade
Real Example Workflow
# Step 1: Add new column to model
class User(db.Model):
id = db.Column(db.Integer,
primary_key=True)
name = db.Column(db.String(100))
email = db.Column(db.String(120)) # NEW!
# Step 2: Create migration
flask db migrate -m "Add email to user"
# Step 3: Apply it
flask db upgrade
View Migration History
flask db history
Check Current Version
flask db current
π― Quick Summary
| Relationship | Example | Key Code |
|---|---|---|
| One-to-Many | Author β Books | relationship() + ForeignKey |
| Many-to-Many | Students β Clubs | Helper table + secondary= |
| One-to-One | Person β Passport | uselist=False |
| Migration | Command | When |
|---|---|---|
| Create | flask db migrate |
After changing models |
| Apply | flask db upgrade |
To update database |
| Undo | flask db downgrade |
To go back |
π You Did It!
You now understand:
- β How tables connect with foreign keys
- β Three types of relationships
- β The magic of backref and back_populates
- β How to safely change your database with migrations
Your data now has a family tree! π³
π‘ Pro Tip: Always test your migrations on a copy of your database before running on production. Safety first!
