Reputation: 95
I have a table I am creating and interacting with using the SQLAlchemy expression engine and I am needing to be able to fetch the values from the ARRAY
column as a python tuple
not a list
. Since the constructor for ARRAY
columns allows you to specify if you want the values as tuples, I ended up just reflecting the table out of the database, looking for ARRAY
columns, replacing them with an ARRAY
column that has the appropriate keyword argument and then using that to construct expressions. Like so:
from sqlalchemy import Table, Column, String, MetaData, select
def swapArrayColumns(table):
new_cols = []
for col in table.columns:
if isinstance(col.type, ARRAY):
new_cols.append(Column(col.name, ARRAY(String, as_tuple=True)))
else:
new_cols.append(Column(col.name, col.type))
return new_cols
engine = create_engine('postgresql://localhost:5432/dbname')
meta = MetaData()
table = Table('table_name', meta, autoload=True, autoload_with=engine)
new_cols = swapArrayColumns(table)
# delete old meta since we are re-mapping table
del meta
meta = MetaData()
new_table = Table('table_name', meta, *new_cols)
# Now I can use the new table object to generate expressions
sel = select([new_table]).where(new_table.c.foo == 'bar')
rows = list(engine.execute(sel))
Since this gets used quite a lot, I'm wondering if there's a more elegant way of accomplishing this same thing perhaps by creating a custom sqlalchemy dialect that just does this for me. All I really want is my ARRAY
columns to come back as python tuple
s by default.
Upvotes: 4
Views: 1762
Reputation: 10397
could look at using a custom sqlalchemy type, something like this:
from sqlalchemy.dialects.postgresql import ARRAY,
class Tuple(types.TypeDecorator):
impl = ARRAY
def process_bind_param(self, value, dialect):
return list(value)
def process_result_value(self, value, dialect):
return tuple(value)
and in the model itself (using declarative):
class MyModel(Base):
id = Column(Integer, primary_key=True)
data = Column(Tuple)
Another way perhaps would be to sub-class ARRAY:
from sqlalchemy.dialects.postgresql import ARRAY as PG_ARRAY
class ARRAY(PG_ARRAY):
def __init__(self, *args, **kwargs):
super(PG_ARRAY, self ).__init__(*args, *kwargs)
self.as_tuple = True
Upvotes: 1