Existe uma maneira conveniente de apelido única conflitantes colunas ao juntar tabelas em SQLAlchemy?
-
06-07-2019 - |
Pergunta
Às vezes é útil para mapear uma classe contra um join
em vez de uma única tabela ao usar SQLAlchemy ' s extensão declarativa. Quando os nomes das colunas colidem, geralmente em um um-para-muitos, porque todas as chaves primárias são nomeados id
por padrão, você pode usar .alias()
prefixar cada coluna com o nome da tabela. Isso é inconveniente se você já tiver código que assume a sua classe mapeada tem nomes não-prefixado escrita.
Por exemplo:
from sqlalchemy.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
tem id
, propriedades fkey
com cada mapeamento de nome para a primeira tabela na junção que usa o nome substituído, então a classe mapeada não expõe chave primária da t2
. ST2
tem t1_id
, t2_id
e t2_fkey
propriedades.
Existe uma maneira conveniente de apelido apenas algumas das colunas de cada tabela na join
assim a classe mapeada expõe os nomes das propriedades mais convenientes não prefixado para a maioria das colunas mapeadas?
Solução
Você pode criar alias para cada coluna separadamente com seu método label()
. Portanto, é possível algo semelhante ao seguinte (não testado):
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))