mrkeyoor.com_
Sat 08 Aug 17:39 UTC
PyPIDataupdated 08 Aug 2026

sqlalchemy-utils

SQLAlchemy-Utils is a broad add-on toolbox for SQLAlchemy. It provides custom column types for choices, email addresses, URLs, IPs, UUIDs, passwords, encrypted strings, phone numbers, colors, locales, ranges, and search vectors; helpers for creating and inspecting databases; ORM inspection functions; automatic coercion listeners; timestamp and repr mixins; aggregate attributes; generic relationships; and database views. You adopt individual pieces, not a replacement ORM.

Verdict

Still valuable when several of its types and ORM helpers remove real repeated work. Install it selectively and with explicit extras; for one utility or an async-only service, local SQLAlchemy 2 code is usually easier to reason about.

API stability4/5Version 0.42.1 still supports SQLAlchemy 1.4 and exposes long-standing types and functions with familiar names. The breadth cuts both ways: compatibility spans mapper events, dialects, type decorators, and inspection internals, and the docs already deprecate EncryptedType in favor of StringEncryptedType. Pinning around SQLAlchemy upgrades remains prudent.
Docs4/5Read the Docs has dedicated sections for data types, database, foreign-key and ORM helpers, generic relationships, listeners, aggregates, observers, views, model mixins, testing, and utility classes, with substantial source docstrings. Several index pages are mostly autodoc lists, examples retain older query style, and optional dependency and async boundaries take work to assemble.
Maintenance4/5PyPI's current 0.42.1 artifacts were uploaded in December 2025, the repository was pushed in July 2026, and it is not archived. GitHub reports 226 open issues and pull requests, a large queue for a 1,342-star project, but continuing Python and SQLAlchemy compatibility changes show the package is maintained rather than frozen.
Ecosystem4/5The supplied weekly figure is 6,838,453 downloads and the repository has 1,342 stars. It covers a wide set of SQLAlchemy use cases and publishes named extras for Babel, Arrow, Pendulum, intervals, phones, passwords, colors, URLs, time zones, and encryption. Its reach is substantial, though every optional type adds another project's API and release cycle.

Use it if

  • Your SQLAlchemy models repeatedly need value-object column types such as ChoiceType, URLType, PasswordType, UUIDType, or PhoneNumberType
  • Your test or administration code needs portable database_exists, create_database, or drop_database helpers
  • You need mapper inspection, deterministic ordering, change detection, generic repr, timestamp, aggregate, or view utilities already implemented against SQLAlchemy internals
  • You accept optional dependencies and global mapper listeners to gain automatic coercion from scalar assignment to richer Python values
Skip it if

Setup reality

`pip install sqlalchemy-utils` installs SQLAlchemy-Utils and requires SQLAlchemy 1.4 or newer on Python 3.9 or newer. That base install does not include most libraries behind richer types. PyPI defines extras such as `password` for passlib, `url` for furl, `phone` for phonenumbers, `color` for colour, `arrow`, `pendulum`, `babel`, `timezone`, `intervals`, and `encrypted` for cryptography. A model can import successfully and then fail when a chosen type is constructed or return plain strings instead of value objects when its optional library is absent, so declare the exact extras your models use. Automatic coercion is opt-in through `force_auto_coercion()` and must be called before models are configured; without it, assignment-time validation and convenient value objects may not happen. With no mapper argument it attaches a listener to every SQLAlchemy mapper in the process, which can surprise applications that host multiple model sets or test suites. Custom types still need Alembic review: their physical storage is commonly String, Unicode, Text, or binary, and autogenerated migrations may need explicit rendering rules. PasswordType needs passlib scheme policy and migration planning; changing hashes can occur during comparison. StringEncryptedType needs durable key management and does not turn a column into a searchable secure vault. Database create and drop helpers require administrative credentials, open synchronous engines, and have backend-specific behavior; never put drop_database on an application request path. The docs claim full create support for MySQL, PostgreSQL, and SQLite, with other engines more tentative. Pin SQLAlchemy and run mapper, migration, and target-database tests because this package necessarily touches ORM and dialect internals.

Patterns

Check whether a database existscheck-database

from sqlalchemy_utils import database_exists

url = 'postgresql+psycopg://admin:secret@localhost/app_test'
if not database_exists(url):
    raise RuntimeError('test database is missing')

The helper opens a synchronous engine and needs a driver plus enough server access to query database metadata. Do not log credential-bearing URLs.

Create a database for testscreate-test-database

from sqlalchemy_utils import create_database, database_exists

if not database_exists(test_url):
    create_database(test_url, encoding='utf8')

The credentials must be allowed to create databases. Concurrent workers can race this check, so provision unique database names or serialize setup.

Drop an isolated test databasedrop-test-database

from sqlalchemy_utils import database_exists, drop_database

if database_exists(test_url):
    drop_database(test_url)

This is destructive and backend-specific. Validate that test_url points to a disposable database before calling it.

Map an Enum with ChoiceTypechoice-column

from enum import Enum
import sqlalchemy as sa
from sqlalchemy_utils import ChoiceType

class Role(Enum):
    admin = 'admin'
    member = 'member'

role = sa.Column(ChoiceType(Role, impl=sa.String(20)), nullable=False)

ChoiceType stores the enum value through the chosen implementation. Database-level allowed-value constraints still need an explicit constraint or native enum.

Normalize an email columnemail-column

import sqlalchemy as sa
from sqlalchemy_utils import EmailType

email = sa.Column(EmailType, nullable=False, unique=True)

EmailType lowercases values; it does not verify deliverability or replace a database uniqueness strategy for case and collation rules.

Expose URL values as furl objectsurl-column

import sqlalchemy as sa
from sqlalchemy_utils import URLType, force_auto_coercion

force_auto_coercion()
website = sa.Column(URLType)

# Install sqlalchemy-utils[url] so assigned strings coerce to furl values.

Without the furl optional dependency, URLType stores and returns strings, so the richer object behavior is not guaranteed by the base install.

Hash and verify passwordspassword-column

import sqlalchemy as sa
from sqlalchemy_utils import PasswordType, force_auto_coercion

force_auto_coercion()
password = sa.Column(PasswordType(
    schemes=['pbkdf2_sha512'],
), nullable=False)

user.password = plaintext
assert user.password == plaintext

Install sqlalchemy-utils[password]. Choose schemes through a reviewed password policy and never compare or serialize the stored hash as ordinary text.

Enable assignment-time value coercionenable-coercion

from sqlalchemy_utils import force_auto_coercion

force_auto_coercion()
# Define or import mapped model classes after this call.

With no mapper argument this attaches to all SQLAlchemy mappers in the process. Call it once before mapper configuration, not repeatedly per request.

Add created and updated timestampstimestamp-model

import sqlalchemy as sa
from sqlalchemy_utils import Timestamp

class Article(Timestamp, Base):
    __tablename__ = 'article'
    id = sa.Column(sa.Integer, primary_key=True)

The mixin stores naive UTC datetime values and updates through an ORM before_update event; bulk SQL updates can bypass instance events.

Generate a safe model reprmodel-repr

from sqlalchemy_utils import generic_repr

@generic_repr('id', 'email')
class User(Base):
    __tablename__ = 'user'
    # mapped columns here

List only non-secret fields. The helper avoids loading deferred fields, but including password hashes or tokens still leaks them into logs.

Escape user text for a LIKE patternescape-like-query

from sqlalchemy import select
from sqlalchemy_utils import escape_like

needle = escape_like(user_text)
stmt = select(User).where(User.name.ilike(f'%{needle}%', escape='*'))

Pass the same escape character to SQLAlchemy's LIKE expression that escape_like used, or wildcard characters will not be treated literally.

Inspect mapped columns consistentlyinspect-columns

from sqlalchemy_utils import get_columns

for column in get_columns(User):
    print(column.key, column.type)

get_columns accepts several SQLAlchemy objects, but code that depends on mapper metadata should still be covered by tests across SQLAlchemy upgrades.

Alternatives

PackageRegistryPick it when
sqlalchemyPyPIModern built-ins and a few local TypeDecorator or inspection helpers cover your needs without another compatibility layer
sqlmodelPyPIYou want Pydantic-style typed models integrated with SQLAlchemy rather than a bag of ORM utilities
sqlalchemy-mixinsPyPIYour main need is active-record-style CRUD, serialization, smart querying, and model mixins