20 SQLalchemy concepts with Before-and-After Examples
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.