首页 > 解决方案 > SQLAlchemy - 从表定义中删除列

问题描述

假设我想动态设置一个主键。我用一个虚拟键初始化表,因为 SQLAlchemy 似乎需要它。我编写了一个函数,用于根据主索引指定主键,该主索引在所有意图和目的上都表现得像主键。当我试图取消虚拟钥匙时,我的问题就出现了。

我希望能够在表声明后删除我的虚拟键,以便我可以用我的自定义键替换它。但是,我不能仅仅delattr(my_table,'dummy_key')因为会有其他对虚拟键的引用,例如在my_table.__table__.columns其他地方可能还有其他地方。

我的问题是,有没有一种好方法可以从表中删除列定义,同时也删除所有这些其他引用?

目前我这样定义表:

Base = declarative_base(cls=DeferredReflection)

class my_table(Base, TableExtension):
    __tablename__ = "my_table"
    __table_args__ = {'schema': 'my_schema'}
    dummy_key = Column(String(), primary_key=True) #false key, just a placeholder, sqlalchemy requires this

TableExtension添加一个方法:

def set_primary_key(self, column_name, column_type):
    self[column_name] = Column(column_type, primary_key=True)

需要帮助编写此函数:

def remove_column(table, col_name):
    # what should I do here?

我已经有一个获取新密钥的功能,它可以工作:

column_names, column_types = get_primary_index(table)

我通过继承向表中添加了一个方法来分配新键。

table.set_new_keys(column_names, column_types)

然后以通常的方式反映表格:

Base.prepare(engine)

这里最重要?的是如何在不对其余表属性做太多手术的情况下删除列引用。任何意见,将不胜感激。

标签: pythonsqlalchemy

解决方案


SQLAlchemy 没有官方记录的方法来解决这个问题。我深入研究了源代码,这是我学到的:

  1. my_table._columns是一个ColumnCollection
  2. my_table.columnsImmutableColumnCollectionmy_table._columns
  3. my_table.c是一个捷径my_table.columns

ColumnCollectionremove定义了接受Column对象作为参数的方法。所以我对这个问题的解决方案是:

# get the column instance from table object
my_col_instance = [col for col in my_table._columns if col.name == my_column_name][0]
# remove from the ColumnCollection, note that we're removing it from ._columns not .columns
my_table._columns.remove(my_col_instance)
# execute actual ALTER TABLE SQL query to drop the column

推荐阅读