Introduction
SQLAlchemy is a powerful SQL toolkit and Object-Relational Mapping (ORM) library for Python. One useful functionality is controlling the columns in your query results. This tutorial will explore how to exclude specific columns efficiently.
Understanding the Basics
Before diving into column exclusion, ensure you’re familiar with the basic usage of SQLAlchemy, such as creating engine instances, session objects, and defining models which map to the database tables. We’ll look at a simple model throughout our examples:
from sqlalchemy import create_engine, Column, Integer, String, Sequence
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
class User(Base):
__tablename__ = 'users'
id = Column(Integer, Sequence('user_id_seq'), primary_key=True)
name = Column(String(50))
fullname = Column(String(50))
nickname = Column(String(50))
# create an engine and bind it
engine = create_engine('sqlite:///:memory:')
# create a configured "Session" class
Session = sessionmaker(bind=engine)
# create a Session
session = Session()
Base.metadata.create_all(engine)
Excluding Columns with Deferred()
Starting with a common scenario, let’s say we want to retrieve all usernames and full names but exclude the nickname field. We use the deferred()
function to achieve this:
from sqlalchemy.orm import deferred
query = session.query(User).options(deferred(User.nickname))
for user in query.all():
print(user.name, user.fullname)
This technique defers the loading of the nickname
column until it’s specifically accessed. Our query only retrieves the name
and fullname
columns, significantly reducing memory and potentially speeding up the query.
Loading Columns On Demand
If you attempt to access the nickname
attribute later, SQLAlchemy will perform another query to load it. For example:
user = query.first()
print(user.nickname) # Triggers another query to get the nickname
Exclude Columns in the Query
You might be partial to having SQLAlchemy construct a query that doesn’t even select the columns you want to exclude. This can be achieved by not including them in the query()
method:
query = session.query(User.name, User.fullname)
for user in query.all():
print(user.name, user.fullname)
Here, the SELECT statement generated by SQLAlchemy only includes the name
and fullname
columns, so nickname
isn’t even touched by the database engine.
Using the ‘load_only’ Function
Another powerful approach is the load_only
function. This allows you to specify exactly which columns to load and therefore implicitly excludes the others:
from sqlalchemy.orm import load_only
query = session.query(User).options(load_only(User.name, User.fullname))
for user in query.all():
print(user.name, user.fullname)
This method is particularly useful when you have models with many columns and you only need a subset, but you don’t want to list out all of the excluded columns individually.
Advanced Use: Overriding the Query Class
For cases where exclusion of columns is a regular need across different queries, you can override the default Query class to include exclusion functionality by default. This can be a more advanced topic as it requires good understanding of customizing SQLAlchemy classes.
class ExcludingQuery(Query):
def exclude(self, *columns):
return self.with_entities(*[c for c in self.column_descriptions if c['expr'] not in columns])
# Replace the query_property on the Base class
Base.query = session.query_property(query_cls=ExcludingQuery)
# Now you can write queries like:
query = User.query.exclude(User.nickname)
for user in query.all():
print(user.name, user.fullname)
Combining Techniques
In practice, these methods can be combined depending on your exact requirements. It’s important to understand the implications on performance and readability of your code when deciding on an approach.
Conclusion
In summary, SQLAlchemy provides several methods to exclude certain columns from query results, each with its own use cases. The method you choose will depend on your application’s needs, the structure of your database, and your specific performance requirements.