Índice de múltiples columnas al usar la extensión ORM declarativa de sqlalchemy

De acuerdo con la documentación y los comentarios en la clase sqlalchemy.Column , debemos usar la clase sqlalchemy.schema.Index para especificar un índice que contenga varias columnas.

Sin embargo, el ejemplo muestra cómo hacerlo utilizando directamente el objeto Tabla de esta manera:

 meta = MetaData() mytable = Table('mytable', meta, # an indexed column, with index "ix_mytable_col1" Column('col1', Integer, index=True), # a uniquely indexed column with index "ix_mytable_col2" Column('col2', Integer, index=True, unique=True), Column('col3', Integer), Column('col4', Integer), Column('col5', Integer), Column('col6', Integer), ) # place an index on col3, col4 Index('idx_col34', mytable.c.col3, mytable.c.col4) 

¿Cómo deberíamos hacerlo si usamos la extensión ORM declarativa?

 class A(Base): __tablename__ = 'table_A' id = Column(Integer, , primary_key=True) a = Column(String(32)) b = Column(String(32)) 

Me gustaría un índice en la columna “a” y “b”.

esos son solo objetos de Column , índice = la bandera verdadera funciona normalmente:

 class A(Base): __tablename__ = 'table_A' id = Column(Integer, primary_key=True) a = Column(String(32), index=True) b = Column(String(32), index=True) 

si desea un índice compuesto, nuevamente, la Table está presente aquí como de costumbre, simplemente no tiene que declararla, todo funciona de la misma manera (asegúrese de estar en los últimos 0.6 o 0.7 para que el contenedor Aa declarativo se interprete como una Column después de que se complete la statement de clase):

 class A(Base): __tablename__ = 'table_A' id = Column(Integer, primary_key=True) a = Column(String(32)) b = Column(String(32)) Index('my_index', Aa, Ab) 

En 0.7, el Index puede estar en los argumentos de la Table , que con declarativo es a través de __table_args__ :

 class A(Base): __tablename__ = 'table_A' id = Column(Integer, primary_key=True) a = Column(String(32)) b = Column(String(32)) __table_args__ = (Index('my_index', "a", "b"), ) 

Para completar la respuesta de @zzzeek.

Si desea agregar un índice compuesto con DESC y usar el método declarativo ORM, puede hacer lo siguiente.

Además, estaba luchando con la documentación de los índices funcionales de SQSAlchemy, tratando de encontrar una forma de sustituir mytable.c.somecol .

 from sqlalchemy import Index Index('someindex', mytable.c.somecol.desc()) 

Podemos usar la propiedad modelo y llamar a .desc() en ella:

 from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class GpsReport(db.Model): __tablename__ = 'gps_report' id = db.Column(db.Integer, db.Sequence('gps_report_id_seq'), nullable=False, autoincrement=True, server_default=db.text("nextval('gps_report_id_seq'::regclass)")) timestamp = db.Column(db.DateTime, nullable=False, primary_key=True) device_id = db.Column(db.Integer, db.ForeignKey('device.id'), primary_key=True, autoincrement=False) device = db.relationship("Device", back_populates="gps_reports") # Indexes __table_args__ = ( db.Index('gps_report_timestamp_device_id_idx', timestamp.desc(), device_id), ) 

Si usas Alembic, estoy usando Flask-Migrate, genera algo como:

 from alembic import op import sqlalchemy as sa # Added manually this import from sqlalchemy.schema import Sequence, CreateSequence def upgrade(): # ### commands auto generated by Alembic - please adjust! ### # Manually added the Sequence creation op.execute(CreateSequence(Sequence('gps_report_id_seq'))) op.create_table('gps_report', sa.Column('id', sa.Integer(), server_default=sa.text("nextval('gps_report_id_seq'::regclass)"), nullable=False), sa.Column('timestamp', sa.DateTime(), nullable=False)) sa.Column('device_id', sa.Integer(), autoincrement=False, nullable=False), op.create_index('gps_report_timestamp_device_id_idx', 'gps_report', [sa.text('timestamp DESC'), 'device_id'], unique=False) def downgrade(): # ### commands auto generated by Alembic - please adjust! ### op.drop_index('gps_report_timestamp_device_id_idx', table_name='gps_report') op.drop_table('gps_report') # Manually added the Sequence removal op.execute(sa.schema.DropSequence(sa.Sequence('gps_report_id_seq'))) # ### end Alembic commands ### 

Finalmente, debe tener la siguiente tabla e índices en su base de datos PostgreSQL:

 psql> \d gps_report; Table "public.gps_report" Column | Type | Collation | Nullable | Default -----------------+-----------------------------+-----------+----------+---------------------------------------- id | integer | | not null | nextval('gps_report_id_seq'::regclass) timestamp | timestamp without time zone | | not null | device_id | integer | | not null | Indexes: "gps_report_pkey" PRIMARY KEY, btree ("timestamp", device_id) "gps_report_timestamp_device_id_idx" btree ("timestamp" DESC, device_id) Foreign-key constraints: "gps_report_device_id_fkey" FOREIGN KEY (device_id) REFERENCES device(id)