Índice de varias columnas cuando se usa la extensión ORM declarativa de sqlalchemy

5 minutos de lectura

avatar de usuario
yorjo

De acuerdo a la documentación y los comentarios en el sqlalchemy.Column clase, deberíamos usar la clase sqlalchemy.schema.Index para especificar un índice que contiene varias columnas.

Sin embargo, el ejemplo muestra cómo hacerlo usando 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”.

  • La pregunta es un poco confusa acerca de si desea múltiples índices o un solo índice en varias columnas (y estaba más confundido antes de editarlo; originalmente pedía deliciosamente “un índice que contiene múltiples índices múltiples”). Pero no importa, supongo, ya que la respuesta de zzzeek aborda ambos casos.

    –Mark Amery

    5 de enero de 2018 a las 14:12


  • La pregunta no indica si el índice conjunto debe ser único o no.

    – Pynchia

    18 de noviembre de 2021 a las 9:11

esos son solo Column objetos, index=True flag 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, de nuevo Table está presente aquí como de costumbre, simplemente no tiene que declararlo, todo funciona igual (asegúrese de estar en 0.6 o 0.7 reciente para que el contenedor Aa declarativo se interprete como un Column después de completar la declaración 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', A.a, A.b)

En 0.7 el Index puede estar en el Table argumentos también, 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"), )

  • Gracias, actualicé a 0.7 y usando el argumentos_tabla funciona bien

    – yorjo

    12 de julio de 2011 a las 14:57

  • ¿Qué sucede si tiene un diccionario para table_args como el que tengo actualmente? argumentos_tabla = {‘mysql_engine’:’InnoDB’}

    –Nick Holden

    1 de septiembre de 2011 a las 8:39

  • @Mella sqlalchemy.org/docs/orm/extensions/…

    –Joe Holloway

    12/10/2011 a las 20:30

  • Así que supongo que puedo hacer argumentos_tabla = (Índice(‘mi_índice’, “a”, “b”),{‘mysql_engine’:’InnoDB’})

    –Nick Holden

    19 de octubre de 2011 a las 11:21


  • @RyanChou docs.sqlalchemy.org/en/latest/orm/extensions/declarative/… “Los argumentos de palabras clave se pueden especificar con el formulario anterior especificando el último argumento como un diccionario”

    – zzzeek

    23 de octubre de 2017 a las 16:18

avatar de usuario
Mickael

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 Índices funcionales documentación de SQLAlchemy, tratando de averiguar cómo sustituir mytable.c.somecol.

from sqlalchemy import Index

Index('someindex', mytable.c.somecol.desc())

Podemos simplemente usar la propiedad del modelo y llamar .desc() en eso:

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 usa 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)

  • No puedo usar los atributos de clase dentro del Index funcion

    – Rickerp

    18 de agosto de 2021 a las 14:52

¿Ha sido útil esta solución?