20 SQLalchemy concepts with Before-and-After Examples

Anix LynchAnix Lynch
12 min read

1. Connecting to a Database πŸ”Œ

Boilerplate Code:

from sqlalchemy import create_engine

engine = create_engine('sqlite:///mydatabase.db')

Use Case: Connect to a database (e.g., SQLite, PostgreSQL, MySQL) to perform queries and operations.

Goal: Establish a connection to a database using SQLAlchemy’s create_engine. 🎯

Sample Code:

from sqlalchemy import create_engine

engine = create_engine('sqlite:///mydatabase.db')

Before Example:
You manually write database connection logic and handle the low-level details of managing connections. πŸ˜•

Manual connection setup, error-prone and inconsistent across databases.

After Example:
With SQLAlchemy’s create_engine, you can easily connect to any supported database with a single line of code. πŸ”Œ

$ python
# Output: Connection to SQLite database established successfully.

Challenge: 🌟 Connect to a different database system, like PostgreSQL or MySQL, and query data.


2. Defining a Table πŸ“

Boilerplate Code:

from sqlalchemy import Column, Integer, String, MetaData, Table

metadata = MetaData()

users_table = Table(
    'users', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
    Column('age', Integer)
)

Use Case: Define the structure of a database table in Python code.

Goal: Use SQLAlchemy’s ORM to define tables using Table, Column, and various data types. 🎯

Sample Code:

from sqlalchemy import Column, Integer, String, MetaData, Table

metadata = MetaData()

users_table = Table(
    'users', metadata,
    Column('id', Integer, primary_key=True),
    Column('name', String),
    Column('age', Integer)
)

Before Example:
You manually create tables using raw SQL, making it hard to maintain and scale. πŸ˜“

Creating tables manually using raw SQL queries.

After Example:
With SQLAlchemy, table schemas are defined in Python, and SQLAlchemy translates them into the corresponding SQL queries. πŸ“

$ python
# Output: Table "users" defined with columns for ID, name, and age.

Challenge: 🌟 Define a more complex table with additional data types like DateTime, Boolean, or ForeignKey.


3. Creating Tables in the Database πŸ—οΈ

Boilerplate Code:

metadata.create_all(engine)

Use Case: Automatically create tables in your connected database based on the defined schema.

Goal: Use SQLAlchemy’s create_all() to generate tables based on your schema. 🎯

Sample Code:

metadata.create_all(engine)

Before Example:
You manually create tables using SQL commands in your database interface. πŸ˜•

Executing raw SQL to create tables, time-consuming and error-prone.

After Example:
With SQLAlchemy, tables are created automatically in the database based on your schema definition. πŸ—οΈ

$ python
# Output: Tables created in the database based on the defined schema.

Challenge: 🌟 Try creating multiple tables at once, including those with foreign key relationships.


4. Inserting Data βž•

Boilerplate Code:

insert_stmt = users_table.insert().values(id=1, name="John", age=30)
conn = engine.connect()
conn.execute(insert_stmt)

Use Case: Insert new records into a database table.

Goal: Insert data using SQLAlchemy’s insert() method. 🎯

Sample Code:

insert_stmt = users_table.insert().values(id=1, name="John", age=30)
conn = engine.connect()
conn.execute(insert_stmt)

Before Example:
You manually write SQL insert statements, which can be tedious and repetitive. πŸ˜•

INSERT INTO users (id, name, age) VALUES (1, 'John', 30);

After Example:
With SQLAlchemy, data is inserted in a programmatic way, and it’s easier to handle different databases. βž•

$ python
# Output: Data inserted into the users table.

Challenge: 🌟 Insert multiple rows at once using a loop or a bulk insert method.


5. Querying Data πŸ•΅οΈβ€β™‚οΈ

Boilerplate Code:

select_stmt = users_table.select().where(users_table.c.name == 'John')
conn = engine.connect()
result = conn.execute(select_stmt)
for row in result:
    print(row)

Use Case: Retrieve data from a database table.

Goal: Use SQLAlchemy’s select() method to query data with conditions. 🎯

Sample Code:

select_stmt = users_table.select().where(users_table.c.name == 'John')
conn = engine.connect()
result = conn.execute(select_stmt)
for row in result:
    print(row)

Before Example:
You write raw SQL queries to retrieve data, which can be difficult to maintain for complex queries. πŸ˜•

SELECT * FROM users WHERE name = 'John';

After Example:
With SQLAlchemy, queries are more readable and flexible, and they work across different database engines. πŸ•΅οΈβ€β™‚οΈ

$ python
# Output: Retrieved data for the user "John".

Challenge: 🌟 Write a query that selects multiple users based on more complex conditions (e.g., age greater than 25).


6. Updating Data ✍️

Boilerplate Code:

update_stmt = users_table.update().where(users_table.c.id == 1).values(name='Jane')
conn = engine.connect()
conn.execute(update_stmt)

Use Case: Update existing data in a table.

Goal: Use SQLAlchemy’s update() method to modify existing records. 🎯

Sample Code:

update_stmt = users_table.update().where(users_table.c.id == 1).values(name='Jane')
conn = engine.connect()
conn.execute(update_stmt)

Before Example:
You manually write SQL update statements, which can become cumbersome for multiple fields or complex conditions. πŸ˜•

UPDATE users SET name = 'Jane' WHERE id = 1;

After Example:
With SQLAlchemy, updates are more straightforward and consistent across different database systems. ✍️

$ python
# Output: User with ID 1 updated to have the name "Jane".

Challenge: 🌟 Update multiple rows based on a range of values, and verify the changes.


7. Deleting Data ❌

Boilerplate Code:

delete_stmt = users_table.delete().where(users_table.c.id == 1)
conn = engine.connect()
conn.execute(delete_stmt)

Use Case: Remove data from a table.

Goal: Use SQLAlchemy’s delete() method to delete records based on conditions. 🎯

Sample Code:

delete_stmt = users_table.delete().where(users_table.c.id == 1)
conn = engine.connect()
conn.execute(delete_stmt)

Before Example:
You manually write SQL delete statements, which can be dangerous if not handled carefully. 😟

DELETE FROM users WHERE id = 1;

After Example:
With SQLAlchemy, deletions are handled in a more controlled and flexible way. ❌

$ python
# Output: User with ID 1 deleted from the users table.

Challenge: 🌟 Write a delete statement that removes records based on a more complex condition, like age or name.


8. Creating a Relationship (Foreign Keys) πŸ”—

Boilerplate Code:

from sqlalchemy import ForeignKey

posts_table = Table(
    'posts', metadata,
    Column('id', Integer, primary_key=True),
    Column('user_id', Integer, ForeignKey('users.id')),
    Column('content', String)
)

Use Case: Establish relationships between tables using foreign keys.

Goal: Use SQLAlchemy to define a relationship between tables via foreign keys. 🎯

Sample Code:

from sqlalchemy import ForeignKey

posts_table = Table(
    'posts', metadata,
    Column('id', Integer, primary_key=True),
    Column('user_id', Integer, ForeignKey('users.id')),
    Column('content', String)
)

Before Example:
You manually write foreign key constraints using raw SQL, which can lead to errors. πŸ˜•

CREATE TABLE posts (id INTEGER, user_id INTEGER, FOREIGN KEY(user_id) REFERENCES users(id));

After Example:
With SQLAlchemy, relationships between tables are handled seamlessly with the ORM. πŸ”—

$ python
# Output: Foreign key relationship created between users and posts tables.

Challenge: 🌟 Create a many-to-many relationship between two

continuing:

tables and implement the logic to query data from both.


9. Using ORM (Object Relational Mapper) πŸ›οΈ

Boilerplate Code:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)

Use Case: Map Python classes to database tables.

Goal: Use SQLAlchemy’s ORM to represent tables as Python classes for easier query manipulation. 🎯

Sample Code:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    id = Column(Integer, primary_key=True)
    name = Column(String)

Before Example:
You write raw SQL queries to interact with database tables, making it harder to manage changes. πŸ˜“

Writing manual SQL queries for every interaction with tables.

After Example:
With the ORM, you can query the database using Python objects, making it easier to manage your data model. πŸ›οΈ

$ python
# Output: User class defined and mapped to the users table.

Challenge: 🌟 Write queries using SQLAlchemy’s ORM to insert, query, update, and delete data.


10. Querying with ORM πŸ”

Boilerplate Code:

session.query(User).filter(User.name == 'John').all()

Use Case: Retrieve records using SQLAlchemy’s ORM rather than raw SQL queries.

Goal: Use SQLAlchemy’s ORM to query data using Python objects. 🎯

Sample Code:

users = session.query(User).filter(User.name == 'John').all()
for user in users:
    print(user.name)

Before Example:
You manually write SQL queries to fetch data, which can become repetitive and difficult to maintain. πŸ˜“

SELECT * FROM users WHERE name = 'John';

After Example:
With SQLAlchemy’s ORM, you use simple Python expressions to query the database. πŸ”

$ python
# Output: Retrieved users with the name "John".

Challenge: 🌟 Write a query using the ORM to retrieve users based on multiple conditions (e.g., name and age).

Here are the SQLAlchemy examples 11-20, following the before-and-after format for data science or machine learning projects:


11. Joining Tables πŸ”—

Boilerplate Code:

session.query(User, Post).join(Post, User.id == Post.user_id).all()

Use Case: Retrieve data from multiple related tables using joins.

Goal: Use SQLAlchemy's ORM to perform SQL joins and retrieve data from related tables. 🎯

Sample Code:

session.query(User, Post).join(Post, User.id == Post.user_id).all()

Before Example:
You manually write SQL queries for joins, which can be complex and hard to manage in large projects. πŸ˜•

SELECT * FROM users JOIN posts ON users.id = posts.user_id;

After Example:
With SQLAlchemy, you use Python objects to perform joins easily, making queries more intuitive. πŸ”—

$ python
# Output: Users and their posts retrieved via join.

Challenge: 🌟 Try joining three tables together (e.g., users, posts, comments) and fetching data from all of them.


12. Executing Raw SQL Queries πŸ› οΈ

Boilerplate Code:

result = engine.execute("SELECT * FROM users")
for row in result:
    print(row)

Use Case: Execute raw SQL queries when needed.

Goal: Use SQLAlchemy to run raw SQL queries when ORM abstractions are not enough. 🎯

Sample Code:

result = engine.execute("SELECT * FROM users")
for row in result:
    print(row)

Before Example:
Sometimes, ORM queries don't cover all use cases, and you need raw SQL for more complex queries. πŸ˜•

Manually executing SQL outside of SQLAlchemy’s ORM framework.

After Example:
With SQLAlchemy, you can still execute raw SQL when needed, while leveraging ORM features for most operations. πŸ› οΈ

$ python
# Output: Raw SQL query executed, users retrieved.

Challenge: 🌟 Write and execute a raw SQL query for complex joins, aggregations, or window functions.


13. Querying with Filters πŸ”

Boilerplate Code:

session.query(User).filter(User.age > 30).all()

Use Case: Filter data based on conditions using SQLAlchemy's ORM.

Goal: Use filter() to add conditions to your queries. 🎯

Sample Code:

users_over_30 = session.query(User).filter(User.age > 30).all()
for user in users_over_30:
    print(user.name)

Before Example:
You manually construct SQL queries with WHERE clauses, making them prone to errors for large datasets. πŸ˜•

SELECT * FROM users WHERE age > 30;

After Example:
With SQLAlchemy’s ORM, adding filters is straightforward and clean. πŸ”

$ python
# Output: All users older than 30 retrieved.

Challenge: 🌟 Write a query with multiple filters (e.g., users over 30 and living in a specific city).


14. Aggregations (SUM, AVG, COUNT) πŸ“Š

Boilerplate Code:

from sqlalchemy import func

session.query(func.count(User.id)).scalar()

Use Case: Perform SQL aggregations like COUNT, SUM, AVG.

Goal: Use SQLAlchemy to aggregate data with built-in SQL functions. 🎯

Sample Code:

from sqlalchemy import func

user_count = session.query(func.count(User.id)).scalar()
print(f"Total users: {user_count}")

Before Example:
Manually executing aggregation queries, which can lead to verbose code. πŸ˜•

SELECT COUNT(*) FROM users;

After Example:
With SQLAlchemy’s func, you can easily perform aggregations in Python. πŸ“Š

$ python
# Output: Total users retrieved.

Challenge: 🌟 Perform other aggregations like SUM of user ages or AVG post likes.


15. Order By (Sorting) πŸ—‚οΈ

Boilerplate Code:

session.query(User).order_by(User.name).all()

Use Case: Sort query results by one or more columns.

Goal: Use SQLAlchemy’s order_by() to sort results. 🎯

Sample Code:

sorted_users = session.query(User).order_by(User.name).all()
for user in sorted_users:
    print(user.name)

Before Example:
Sorting data with raw SQL can make queries verbose. πŸ˜•

SELECT * FROM users ORDER BY name;

After Example:
With SQLAlchemy’s ORM, you can easily sort results in a readable manner. πŸ—‚οΈ

$ python
# Output: Users sorted by name.

Challenge: 🌟 Sort by multiple columns, for example by age and name.


16. Limiting Results πŸ”’

Boilerplate Code:

session.query(User).limit(5).all()

Use Case: Retrieve a specific number of records.

Goal: Use limit() to restrict the number of results returned by a query. 🎯

Sample Code:

limited_users = session.query(User).limit(5).all()
for user in limited_users:
    print(user.name)

Before Example:
Manually handling pagination and limiting results in raw SQL. πŸ˜•

SELECT * FROM users LIMIT 5;

After Example:
With SQLAlchemy, limiting results is easy and works across different database systems. πŸ”’

$ python
# Output: First 5 users retrieved.

Challenge: 🌟 Add offset() to your query to skip the first few results (for pagination).


17. Transactions (Commit/Rollback) πŸ”„

Boilerplate Code:

session.add(new_user)
session.commit()

Use Case: Commit changes to the database or roll them back in case of failure.

Goal: Use commit() and rollback() to manage transactions. 🎯

Sample Code:

session.add(new_user)
try:
    session.commit()
except:
    session.rollback()
    raise

Before Example:
You manually manage transactions and error handling, which can be tricky and error-prone. πŸ˜•

Manually writing commit and rollback logic with SQL.

After Example:
With SQLAlchemy, transactions are handled cleanly with commit and rollback methods. πŸ”„

$ python
# Output: Data committed to the database, or rolled back on failure.

Challenge: 🌟 Write a test case that intentionally triggers an error and verify that the transaction is rolled back.


18. Using Sessions πŸ—ƒοΈ

Boilerplate Code:

from sqlalchemy.orm import sessionmaker

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

Use Case: Manage database operations in an isolated session.

Goal: Use SQLAlchemy sessions to interact with the database within an isolated environment. 🎯

Sample Code:

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

Before Example:
Manually managing multiple database connections and commits, which can lead to race conditions. πŸ˜•

Manually handling multiple connections in code.

After Example:
With SQLAlchemy sessions, database operations are isolated and safely handled. πŸ—ƒοΈ

$ python
# Output: Session created, ready for database operations.

Challenge: 🌟 Use multiple sessions to simulate concurrent database operations.


19. Eager Loading (Join Load) ⚑

Boilerplate Code:

from sqlalchemy.orm import joinedload

session.query(User).options(joinedload(User.posts)).all()

Use Case: Retrieve related data in a single query to avoid multiple database calls.

Goal: Use eager loading to improve query performance by joining related tables. 🎯

Sample Code:

from sqlalchemy.orm import joinedload

users_with_posts = session.query(User).options(joinedload(User.posts)).all()
for user in users_with_posts:
    print(user.posts)

Before Example:
You make separate database queries for each related record, resulting in slow performance. πŸ˜•

Multiple queries to retrieve users and their posts.

After Example:
With eager loading, related data is fetched in one query, improving performance. ⚑

$ python
# Output: Users and their posts retrieved in a single query.

Challenge: 🌟 Implement eager loading for deeply nested relationships (e.g., users β†’ posts β†’ comments).


20. Lazy Loading (Deferred Load) πŸ’€

Boilerplate Code:

session.query(User).all()  # No posts loaded yet
for user in users:
    print(user.posts)  #

It looks like we left off with **lazy loading** in SQLAlchemy. Let's finish **concept 20** and wrap up the **SQLAlchemy** examples 11-20!

---

### 20. **Lazy Loading (Deferred Load)** πŸ’€

**Boilerplate Code**:
```python
session.query(User).all()  # No posts loaded yet
for user in users:
    print(user.posts)  # Posts are loaded when accessed

Use Case: Load related data only when it's accessed.

Goal: Use lazy loading to defer loading related data until it is needed, optimizing memory and performance. 🎯

Sample Code:

users = session.query(User).all()  # Posts are not loaded yet
for user in users:
    print(user.posts)  # Posts loaded only when accessed

Before Example:
You load all related records immediately, even if they are not needed, wasting memory and time. πŸ˜•

User data and their posts are all loaded at once, even if posts aren't used in the code.

After Example:
With lazy loading, related data is loaded only when accessed, reducing memory usage and improving efficiency. πŸ’€

$ python
# Output: Users loaded, and posts are only fetched when accessed.

Challenge: 🌟 Implement lazy loading for other related data, like comments or likes, and measure the performance difference.


0
Subscribe to my newsletter

Read articles from Anix Lynch directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Anix Lynch
Anix Lynch