Database Integration and Flask-SQLAlchemy
Flask, being a lightweight web framework, doesn't come with built-in database support, but it can easily integrate with various database systems using extensions. Database integration allows Flask applications to interact with persistent data stores (e.g., relational databases like MySQL, PostgreSQL, SQLite, and NoSQL databases like MongoDB).
Flask supports several tools and libraries for database interaction, with SQLAlchemy being one of the most popular and powerful extensions for working with relational databases. Flask also supports direct integration with other databases via native libraries and third-party extensions.
Flask-SQLAlchemy: Overview
Flask-SQLAlchemy is an extension for Flask that adds support for SQLAlchemy, a powerful Object-Relational Mapping (ORM) library for Python. With Flask-SQLAlchemy, you can work with databases using high-level Python objects instead of writing raw SQL queries.
SQLAlchemy provides two main components:
- Core: Provides the underlying database connection and raw SQL query capabilities.
- ORM: Allows interaction with databases using Python classes that map to database tables.
Flask-SQLAlchemy integrates these components seamlessly into Flask applications, making it easier to manage your database schema and interact with the data.
Setting Up Flask-SQLAlchemy
Installation
To begin using Flask-SQLAlchemy, you need to install the required libraries.
pip install Flask-SQLAlchemy
Configuration
After installation, you need to configure the database URI in the Flask application to tell Flask-SQLAlchemy where to connect. Typically, the database URI is set using the SQLALCHEMY_DATABASE_URI
configuration key. This URI specifies the database type, username, password, host, and database name.
Example: SQLite Database
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
# Set up the database URI (SQLite in this case)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' # SQLite file-based DB
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False # Disable modification tracking to save resources
# Initialize the SQLAlchemy object
db = SQLAlchemy(app)
- SQLALCHEMY_DATABASE_URI: Specifies the location of the database.
- SQLALCHEMY_TRACK_MODIFICATIONS: Flask-SQLAlchemy uses signals to track object modifications, but this feature can be disabled to save resources in most applications.
For other databases, the URI changes as follows:
- PostgreSQL:
'postgresql://username:password@localhost/dbname'
- MySQL:
'mysql://username:password@localhost/dbname'
Defining Database Models
A model in Flask-SQLAlchemy is a Python class that represents a table in the database. The class inherits from db.Model
and defines attributes (columns) of the table.
Example: Defining a User Model
class User(db.Model):
id = db.Column(db.Integer, primary_key=True) # Integer column for ID, primary key
username = db.Column(db.String(120), unique=True, nullable=False) # String column for username
email = db.Column(db.String(120), unique=True, nullable=False) # String column for email
password = db.Column(db.String(60), nullable=False) # String column for password
def __repr__(self):
return f"User('{self.username}', '{self.email}')"
In this example:
db.Column
specifies a column in the database.primary_key=True
: Marks theid
field as the primary key.unique=True
: Ensures that the field is unique across all records.nullable=False
: Ensures that the column cannot have null values.- The
__repr__
method provides a string representation for debugging purposes.
Flask-SQLAlchemy automatically translates the class into a corresponding table in the database.
Performing CRUD Operations
Once the model is defined, you can interact with the database and perform CRUD (Create, Read, Update, Delete) operations.
Create
To create a new record, instantiate the model and add it to the database session.
new_user = User(username='johndoe', email='johndoe@example.com', password='password123')
db.session.add(new_user)
db.session.commit() # Commit the transaction to save the record to the database
Read
To query the database, you can use SQLAlchemy's querying capabilities to retrieve records.
Query All Users
users = User.query.all() # Get all users from the User table
Query a Single User by ID
user = User.query.get(1) # Get the user with ID 1
Query with Filters
user = User.query.filter_by(username='johndoe').first() # Get the first user with username 'johndoe'
Update
To update an existing record, fetch the record, modify its attributes, and commit the transaction.
user = User.query.get(1)
user.username = 'johnsmith'
db.session.commit() # Save the changes to the database
Delete
To delete a record, fetch the record and call db.session.delete()
followed by db.session.commit()
.
user = User.query.get(1)
db.session.delete(user)
db.session.commit() # Delete the user record from the database
Database Migrations with Flask-Migrate
Database migrations are an essential part of database management, allowing you to evolve your database schema over time without losing data. Flask-Migrate is an extension that integrates Alembic (a lightweight database migration tool for SQLAlchemy) with Flask.
Installation
pip install Flask-Migrate
Setup
First, initialize the migration repository:
from flask_migrate import Migrate
migrate = Migrate(app, db)
In your application's entry point (app.py
), you also need to create the migration commands:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from flask_migrate import Migrate
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db'
db = SQLAlchemy(app)
migrate = Migrate(app, db)
Now you can use the following commands for migration:
-
Initialize migration scripts:
flask db init
-
Create a migration script:
flask db migrate -m "Initial migration"
-
Apply the migration:
flask db upgrade
-
Rollback to previous migrations:
flask db downgrade
Handling Database Relationships
Flask-SQLAlchemy supports defining relationships between models using db.relationship()
and db.ForeignKey()
.
Example: One-to-Many Relationship
Consider a scenario where each User
can have multiple Post
s.
class Post(db.Model):
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(120), nullable=False)
content = db.Column(db.Text, nullable=False)
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), nullable=False)
user = db.relationship('User', back_populates='posts')
User.posts = db.relationship('Post', back_populates='user', lazy=True)
In this example:
user_id
is a foreign key that refers to theUser
table.- The
db.relationship()
method is used to define a relationship betweenUser
andPost
.
Example: Many-to-Many Relationship
For a many-to-many relationship, you typically use an auxiliary table to represent the connection.
association_table = db.Table('association',
db.Column('user_id', db.Integer, db.ForeignKey('user.id')),
db.Column('group_id', db.Integer, db.ForeignKey('group.id'))
)
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
groups = db.relationship('Group', secondary=association_table, backref=db.backref('users', lazy='dynamic'))
class Group(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(100), unique=True)