Sometimes it is useful to map a class against a join
instead of a single table when using SQLAlchemy's declarative extension. When column names collide, usually in a one-to-many because all primary keys are named id
by default, you can use .alias()
to prefix every column with its table name. That is inconvenient if you've already written code that assumes your mapped class has non-prefixed names.
For example:
from sqla开发者_如何学编程lchemy.ext.declarative import declarative_base
from sqlalchemy import Table, Column, Integer, ForeignKeyConstraint
Base = declarative_base()
t1 = Table('t1',
Base.metadata,
Column('id', Integer, primary_key=True))
t2 = Table('t2',
Base.metadata,
Column('id', Integer, primary_key=True),
Column('fkey', Integer),
ForeignKeyConstraint(['fkey'], [t1.c.id]))
class ST(Base):
__table__ = t1.join(t2)
class ST2(Base):
__table__ = t1.join(t2).alias()
ST
has id
, fkey
properties with each name mapping to the first table in the join that uses the overridden name, so the mapped class does not expose t2
's primary key. ST2
has t1_id
, t2_id
and t2_fkey
properties.
Is there a convenient way to alias only some of the columns from each table in the join
so the mapped class exposes the more convenient non-prefixed property names for most mapped columns?
You can create alias for each column separately with its label()
method. So it's possible something similar to the following (not tested):
from sqlalchemy import select
def alias_dups(join):
dups = set(col.key for col in join.left.columns) & \
set(col.key for col in join.right.columns)
columns = []
for col in join.columns:
if col.key in dups:
col = col.label('%s_%s' % (col.table.name, col.key))
columns.append(col)
return select(columns, from_obj=[join]).alias()
class ST2(Base):
__table__ = alias_dups(t1.join(t2))
精彩评论