ดัชนีหลายคอลัมน์เมื่อใช้ส่วนขยาย ORM ที่เปิดเผยของ sqlalchemy


97

ตามเอกสารประกอบและข้อคิดเห็นในsqlalchemy.Columnคลาสเราควรใช้คลาสsqlalchemy.schema.Indexเพื่อระบุดัชนีที่มีหลายคอลัมน์

อย่างไรก็ตามตัวอย่างแสดงวิธีการทำโดยใช้วัตถุตารางโดยตรงดังนี้:

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)

เราควรทำอย่างไรหากเราใช้ส่วนขยาย ORM ที่เปิดเผย

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

ฉันต้องการดัชนีในคอลัมน์ "a" และ "b"


1
คำถามไม่ชัดเจนเล็กน้อยเกี่ยวกับว่าคุณต้องการดัชนีหลายรายการหรือดัชนีเดียวในหลายคอลัมน์ (และสับสนมากขึ้นก่อนที่ฉันจะแก้ไข - แต่เดิมถามว่า"ดัชนีที่มีหลายดัชนีหลายรายการ" ) แต่ไม่ว่าอย่างไรฉันเดาว่าเนื่องจากคำตอบของ zzzeek กล่าวถึงทั้งสองกรณี
Mark Amery

คำตอบ:


142

สิ่งเหล่านี้เป็นเพียงColumnวัตถุดัชนี = ธง True ทำงานได้ตามปกติ:

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

หากคุณต้องการดัชนีผสมอีกครั้งTableจะปรากฏที่นี่ตามปกติคุณไม่จำเป็นต้องประกาศทุกอย่างทำงานเหมือนเดิม (ตรวจสอบให้แน่ใจว่าคุณใช้ 0.6 หรือ 0.7 ล่าสุดสำหรับกระดาษห่อ Aa ที่ประกาศจะตีความเป็นColumnหลังจากการประกาศคลาสเสร็จสมบูรณ์):

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)

ใน 0.7 Indexสามารถอยู่ในTableอาร์กิวเมนต์ได้เช่นกันซึ่งมีการประกาศผ่าน__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"), )

1
ขอบคุณฉันอัปเดตเป็น 0.7 และการใช้table_args ใช้งานได้ดี
โจ

6
จะเกิดอะไรขึ้นถ้าคุณมีพจนานุกรมสำหรับ table_args เหมือนที่ฉันทำอยู่ table_args = {'mysql_engine': 'InnoDB'}
Nick Holden


7
ดังนั้นฉันเดาว่าฉันสามารถทำtable_args = (ดัชนี ('my_index', "a", "b"), {'mysql_engine': 'InnoDB'})
Nick Holden

1
@RyanChou docs.sqlalchemy.org/th/latest/orm/extensions/declarative/… "สามารถระบุอาร์กิวเมนต์คำหลักด้วยแบบฟอร์มด้านบนโดยระบุอาร์กิวเมนต์สุดท้ายเป็นพจนานุกรม"
zzzeek

13

ให้เสร็จสมบูรณ์ @ zzzeek ของคำตอบ

หากคุณต้องการเพิ่มดัชนีผสมกับ DESC และใช้วิธีการประกาศ ORM คุณสามารถทำได้ดังนี้

นอกจากนี้ผมกำลังดิ้นรนกับดัชนีการทำงานเอกสาร SQSAlchemy mytable.c.somecolพยายามที่จะคิดออกว่าจะเปลี่ยนตัวลงสนาม

from sqlalchemy import Index

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

เราสามารถใช้คุณสมบัติของโมเดลและเรียก.desc()ใช้:

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

ถ้าคุณใช้ Alembic ฉันกำลังใช้ Flask-Migrate มันจะสร้างสิ่งต่างๆเช่น:

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 ###

สุดท้ายคุณควรมีตารางและดัชนีต่อไปนี้ในฐานข้อมูล 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)
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.