SQLAlchemy / Alembic 想要删除并重新创建外键索引

SQLAlchemy / Alembic wanting to drop & re-create index for foreign key

Alembic、SQLAlchemy 和 Python 的新手总数。我已经到了 Alembic 将数据库中的现有对象与我所做的声明 classes 进行比较的地步,并且有一个讨厌的索引(对于外键)Alembic 拒绝留在原地我的初始迁移。

我完全不知道为什么迁移会不断尝试删除并重新创建此索引,如果我离开迁移,我敢打赌无论如何都会失败。另外,如果我不将 class 与数据库进行协调,则每次我自动生成迁移时都可能会出现这种情况。

下面是 upgrade 方法的相关部分:

op.drop_index(
    'vndr_prod_tp_cat_category_fk_idx',
    table_name='vendor_product_types_magento_categories'
)

downgrade方法中:

op.create_index(  
    'vndr_prod_tp_cat_category_fk_idx',
    'vendor_product_types_magento_categories',
    ['magento_category_id'],
    unique=False
)

...这是 table 的 DDL,因为它存在于 MySQL:

CREATE TABLE `vendor_product_types_magento_categories` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `vendor_product_type_id` bigint(20) unsigned NOT NULL,
  `magento_category_id` bigint(20) unsigned NOT NULL,
  `sequence` tinyint(3) unsigned NOT NULL,
  `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `updated_at` timestamp NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`),
  UNIQUE KEY `vendor_product_types_magento_categories_uq` (`vendor_product_type_id`,`magento_category_id`,`sequence`),
  KEY `vndr_prod_tp_cat_category_fk_idx` (`magento_category_id`),
  CONSTRAINT `vndr_prod_tp_cat_magento_category_fk` FOREIGN KEY (`magento_category_id`) REFERENCES `magento_categories` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION,
  CONSTRAINT `vndr_prod_tp_cat_product_type_fk` FOREIGN KEY (`vendor_product_type_id`) REFERENCES `vendor_product_types` (`id`) ON DELETE NO ACTION ON UPDATE NO ACTION
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8

...这是我写的 class:

from sqlalchemy import Column, Integer, UniqueConstraint, ForeignKeyConstraint, Index
from sqlalchemy.dialects.mysql import TIMESTAMP
from sqlalchemy.sql import text
from .base import Base


class VendorProductTypesMagentoCategories(Base):
    __tablename__ = 'vendor_product_types_magento_categories'

    id = Column(Integer, primary_key=True)
    vendor_product_type_id = Column(
        Integer,
        nullable=False
    )
    magento_category_id = Column(
        Integer,
        nullable=False
    )
    sequence = Column(Integer, nullable=False)
    created_at = Column(TIMESTAMP, server_default=text('CURRENT_TIMESTAMP'), nullable=False)
    updated_at = Column(
        TIMESTAMP,
        server_default=text('NULL ON UPDATE CURRENT_TIMESTAMP'),
        nullable=True
    )

    __table_args__ = (
        UniqueConstraint(
            'vendor_product_type_id',
            'magento_category_id',
            'sequence',
            name='vendor_product_types_magento_categories_uq'
        ),
        ForeignKeyConstraint(
            ('vendor_product_type_id',),
            ('vendor_product_types.id',),
            name='vndr_prod_tp_cat_product_type_fk'
        ),
        ForeignKeyConstraint(
            ('magento_category_id',),
            ('magento_categories.id',),
            name='vndr_prod_tp_cat_category_fk_idx'
        ),
    )

    def __repr__(self):
        return '<VendorProductTypesMagentoCategories (id={}, vendor_name={}, product_type={})>'.format(
            self.id,
            self.vendor_name,
            self.product_type
        )

您在 python 代码中将产品外键定义为

    ForeignKeyConstraint(
        ('magento_category_id',),
        ('magento_categories.id',),
        name='vndr_prod_tp_cat_category_fk_idx'
    )

这里使用vndr_prod_tp_cat_category_fk_idx作为外键约束的名称,而不是底层索引的名称,这就解释了sqlalchemy为什么要删除索引。

您应该使用 vndr_prod_tp_cat_product_type_fk 作为外键名称,并有一个单独的 Index() 构造以 vndr_prod_tp_cat_category_fk_idx 作为名称来创建索引。