Skip to main content

SqlAlchemy Enumeration Tables

SQLAlchemy has built-in enum.Enum support, via its column type sqlalchemy.Enum. However, this type relies either on the backend’s enum type, or on a check constraints. Both of these are immutable objects, which are a pain in the butt to modify (only PostgreSQL supports adding values to an enum type, and even then it doesn’t support removing them).

Another often-used pattern to support enums in a database is via a dedicated table that reflects the enum values. This requires updating the table everytime the enum is modified, but doing so is much simpler than replacing a type.

This package allows you to create the enum table, and columns referencing that table, directly from a Python enum class. It also interfaces with Alembic to automatically add INSERT and DELETE statements to your autogenerated migration scripts.

When to use

  1. Only works with Pythons’s enumeration classes, or at least one with a behavior similar to enum.Enum. Does not work with collections of arbitrary entries.

  2. Only works with SqlAlchemy’s declarative ORM system. If you only use SqlAlchemy Core… deal with it.

  3. Better used for frequently updated enumeration classes.

  4. Do not use with another package that provides op.enum_insert and op.enum_delete operations in Alembic.

How to use with SqlAlchemy

import enum
import sqlalchemy as sa
from sqlalchemy.ext.declarative import declarative_base

import enumtables as et

# Create the Python enumeration class
class MyEnum(enum.Enum):
    HELLO = "HELLO"
    WORLD = "WORLD"

Base = declarative_base()

# Create the enumeration table
# Pass your enum class and the SQLAlchemy declarative base to enumtables.EnumTable
MyEnumTable = et.EnumTable(MyEnum, Base)

# Create a model class that uses the enum
class MyModel(Base):
    __tablename__ = "my_model"
    # Pass the enum table (not the enum class) to enumtables.EnumColumn
    # It replaces sqlalchemy.Column, but aside from the enum table,
    # it can take the same parameters.
    # It will automatically create a ForeignKeyConstraint referencing the enum table.
    enum_value = et.EnumColumn(MyEnumTable, primary_key = True)

    # When valued (on an instance of MyModel), enum_value will be an instance of MyEnum.

First, the EnumTable factory takes the enum class and the declarative base class to create the actual ORM class. Then this ORM class is passed to the EnumColumn class to create the column linked to the enum table. The column behaves just as if it had SqlAlchemy’s own Enum type.

On the implementation side, EnumTable is not a class, it’s a factory function that performs Python black magic to create a subclass of the declarative base, and set it up to be a DB table containing the enum items (actually it just has one column item_id of type String).

EnumColumn is a subclass of SqlAlchemy’s Column that gets initialized with a custom type and a foreign key to the enum table.

How to use with Alembic

First add:

import enumtables

at the begining of your env.py file, then add the same line in the imports of your script.py.mako file. The package uses Alembic’s standard hooks to take care of migration generation.

Don’t forget to review the migrations afterwards. Especially make sure that, if the table did not exist before, the op.enum_insert commands are located after the corresponding op.create_table command.

Other uses

Using the enum table class directly

The enum table class behaves like any SqlAlchemy ORM class:

enum_query = session.query(MyEnumTable)
result = enum_query.first()

# The column item_id stores the name of the enum item as a string
enum_name = result.item_id

Adding more columns to the enum tables

Any keyword argument passed to the EnumTable factory becomes a member of the table class. Which means, you can pass anything (like a column) exactly as you would defined a usual ORM class:

BetterEnumTable = et.EnumTable(
    MyEnum,
            Base,

    # tablename is turned into __tablename__
    tablename = "better_enum",

    # Let's add a new column!
    order = sa.Column(sa.Integer, nullable = False),

    # And since it's an ordering number, let's make it unique too.
    __table_args__ = (
        sa.UniqueConstraint('order'),
    ),
)

Metadata

Release files for SqlAlchemy-Enum-Tables 1.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for SqlAlchemy-Enum-Tables 1.1.0
File Size Uploaded Provenance Actions
SqlAlchemy Enum Tables-1.1.0.tar.gz 6.3 kB Without provenance Details for SqlAlchemy Enum Tables-1.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for SqlAlchemy-Enum-Tables 1.1.0
File Interpreter ABI Platform Actions
SqlAlchemy_Enum_Tables-1.1.0-py3-none-any.whl Python 3 none any Details for SqlAlchemy_Enum_Tables-1.1.0-py3-none-any.whl

Total release size: 13.4 kB

Release files / SqlAlchemy Enum Tables-1.1.0.tar.gz

Download URL SqlAlchemy Enum Tables-1.1.0.tar.gz
Size 6.3 kB
Tags Source
SHA-256 checksum
How to use checksums
e788b580c11fecb214c17669f94da597b2043fc8baaee35c9f4af8f82bb6d22f
BLAKE2b-256 checksum
How to use checksums
db205f7e70de7726490bdcb0008bec20d5763ffd5981fdeedb9dfc0d819dfedc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.2

Release files / SqlAlchemy_Enum_Tables-1.1.0-py3-none-any.whl

Download URL SqlAlchemy_Enum_Tables-1.1.0-py3-none-any.whl
Size 7.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
714edc93ed9d2614177e822db7963daccb47b4273224ce709c4579c400186cc5
BLAKE2b-256 checksum
How to use checksums
08622cd04b67fddd36d0bedcbba5c386f2c93334ad3088779bd18426045c1ae6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.2

Security for SqlAlchemy-Enum-Tables 1.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

1.1.0 This release

2 release files No provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page