Sling Academy
Home/SQLAlchemy/SQLAlchemy: Perform Case-Insensitive Filter

SQLAlchemy: Perform Case-Insensitive Filter

Last updated: January 03, 2024

Overview

SQLAlchemy is a powerful and flexible ORM (Object-Relational Mapping) library for Python. It allows developers to work with databases using Python classes and objects, abstracting the raw SQL queries that interact with the database engine.

In this tutorial, you will learn how to apply case-insensitive filters in SQLAlchemy, which is an essential technique for building robust database queries that are not affected by the case of the data.

When you need to filter query results, the case of the values can matter. Sometimes, we want our filter to be case-insensitive to provide better usability and reliability. In SQLAlchemy, this is achieved using various functions and methods such as func.lower().

Basic Filtering with SQLAlchemy

Let’s start with a basic filtering example where case sensitivity is the default behavior. To set up our environment, we first need to define our model and create a session:

from sqlalchemy import create_engine, Column, String
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'
    username = Column(String, primary_key=True)

# Engine/connection setup
engine = create_engine('sqlite:///example.db', echo=True)
Base.metadata.create_all(engine)

# Creating a session
Session = sessionmaker(bind=engine)
session = Session()

Now let’s add a filter to our queries in the standard case-sensitive way:

# Standard case-sensitive filter
user = session.query(User).filter(User.username == 'JohnDoe').first()

Case-Insensitive Filtering with SQLAlchemy

To implement a case-insensitive filter, you can use the func.lower() from SQLAlchemy:

from sqlalchemy import func

# Case-insensitive filter using func.lower()
user = session.query(User).filter(func.lower(User.username) == func.lower('JohnDoe')).first()

This query will ignore case when filtering the username field. It’s particularly useful when dealing with user input where the case of the input might vary.

Advanced Case-Insensitive Queries

As you become more familiar with SQLAlchemy, you might encounter more complex cases. For example, you might want to perform a case-insensitive search across multiple fields or use pattern matching. Here’s how to extend our case-insensitive logic to those scenarios.

# Case-insensitive filter across multiple fields using or_
from sqlalchemy import or_

user = session.query(User).filter(
    or_(
        func.lower(User.username) == func.lower('JohnDoe'),
        func.lower(User.email) == func.lower('[email protected]')
    )
).first()

# Case-insensitive LIKE pattern matching
user = session.query(User).filter(
    func.lower(User.username).like(func.lower('%doe%'))
).all()

You can also integrate these filters with other SQLAlchemy features for even more powerful querying.

Using Hybrid Properties for Case-Insensitive Filtering

Hybrid properties offer a way to define properties on Python classes that behave like Column properties on the database level. We can use this to streamline our case-insensitive filters.

from sqlalchemy.ext.hybrid import hybrid_property

class User(Base):
    __tablename__ = 'users'
    _username = Column('username', String)

    @hybrid_property
    def username(self):
        return self._username.lower()

    @username.expression
    def username(cls):
        return func.lower(cls._username)

# Filtering by hybrid property
user = session.query(User).filter(User.username == 'johndoe').first()

Conclusion

In conclusion, performing case-insensitive filters in SQLAlchemy is a versatile practice that can significantly enhance the user experience by removing restrictions imposed by the case-sensitivity of strings in databases. Utilizing the func.lower() function to normalize the cases of the column and the input values enables comparison on a level playing field. As your requirements grow more complex, the power of SQLAlchemy’s functionality shines through with features like hybrid properties and pattern matching that can keep your queries both robust and efficient.

Next Article: SQLAlchemy: How to Set a Timeout for Queries (Max Execution Time)

Previous Article: How to enable/disable auto-commit in SQLAlchemy

Series: SQLAlchemy Tutorials: From Basic to Advanced

SQLAlchemy

You May Also Like

  • SQLAlchemy: Counting rows for each category (2 approaches)
  • SQLAlchemy: Adding a calculated column to SELECT query
  • SQLAlchemy: Grouping data on multiple columns
  • SQLAlchemy: How to temporarily delete a row
  • SQLAlchemy Composite Indexes: The Complete Guide
  • Full-Text Search in SQLAlchemy: The Ultimate Guide
  • SQLAlchemy: What if you don’t close database connections?
  • SQLAlchemy: How to Remove FOREIGN KEY Constraints (2 Ways)
  • SQLAlchemy: How to Create and Use Temporary Tables
  • SQLAlchemy: Saving Categories and Subcategories in the Same Table
  • SQLAlchemy: How to Automatically Delete Old Records
  • Weighted Random Selection in SQLAlchemy: An In-Depth Guide
  • SQLAlchemy: created_at and updated_at columns
  • How to Use Regular Expressions in SQLAlchemy
  • SQLAlchemy: Ways to Find Results by a Keyword
  • SQLAlchemy: How to Connect to MySQL Database
  • SQLAlchemy: How to Bulk Insert Data into a Table
  • SQLAlchemy: How to Update a Record by ID
  • SQLAlchemy: Singular vs Plural Table Names