SQLAlchemy composite type
Asked Answered
T

1

7

Does SQLAlchemy support PostgreSQL's composite types (http://www.postgresql.org/docs/devel/static/rowtypes.html)? I found it has something similar (sqlalchemy.orm.composite), but as far as I can see, it's not good enough for my purpose.

I'd like to make a separate type, for example Amount having value and currency, and then be able to refer to it repeatedly, and possibly multiple times from the same class:

class Transfer(base):
    __tablename__ = "transfer"
    source_amount = Column(Amount)
    target_amount = Column(Amount)

All the examples I've seen (for example this one) require me to specify the names of the columns, which makes such approach as above impossible (column names would clash).

Besides, I'd rather have one column per Amount instead of two (since value doesn't really make much sense without currency, I'd rather the database take care of never separating or mixing them). It seems Postgres can do that, I just need a way to explain to SQLAlchemy what I need. I tried reading http://docs.sqlalchemy.org/en/latest/core/custom_types.html, but it seems to focus on augmenting existing types, not creating new ones as composites (I don't know what to put under impl).

Maybe I should let go of SQLAlchemy and communicate with psycopg2 directly? It has a psycopg2.extras.register_composite function, but once I do that, I still don't know how to convince SQLAlchemy to recognize the registration. I would probably have to somehow pass the cursor from psycopg2 to SQLAlchemy, but I don't know how to do that.

Tumblebug answered 14/4, 2015 at 12:4 Comment(0)
N
6

SQLalchemy does not support postgresql composite types natively.

However, sqlalchemy_utils supports postgresql composite types natively.

Here's an example from their documentation:

from collections import OrderedDict
    
import sqlalchemy as sa
from sqlalchemy_utils import CompositeType, CurrencyType

class Account(Base):
    __tablename__ = 'account'
    id = sa.Column(sa.Integer, primary_key=True)
    balance = sa.Column(
        CompositeType(
            'money_type',
            [
                sa.Column('currency', CurrencyType),
                sa.Column('amount', sa.Integer)
            ]
        )
    )

Usage:

session.query(Account).filter(Account.balance.amount > 5000)
Nephrotomy answered 27/9, 2017 at 20:17 Comment(2)
Note: There is an open issue with sqlalchemy_utils' Compositive type: github.com/kvesteri/sqlalchemy-utils/issues/319Teddman
From sqlalchemy_utils docs - When you already have your database set up you should call register_composites() after you’ve set up all models.Beachcomber

© 2022 - 2024 — McMap. All rights reserved.