【问题标题】:add column to SQLAlchemy Table将列添加到 SQLAlchemy 表
【发布时间】:2021-07-24 02:37:26
【问题描述】:

我使用 SQLAlchemy 创建了一个表,但忘记添加一列。我基本上想这样做:

users.addColumn('user_id', ForeignKey('users.user_id'))

这个的语法是什么?我在文档中找不到它。

【问题讨论】:

  • 有些相关:sqlalchemy.Table.append_column()append_constraint()。这对于在单独的调用中构建 sqlalchemy 的元数据很有用,但对于更改数据库对象(您需要迁移,如该问题的答案中所讨论的那样)没有用

标签: python terminal sqlalchemy


【解决方案1】:

我也有同样的问题,一想到只为这件小事使用迁移库就让我
颤抖。无论如何,这是我迄今为止的尝试:

def add_column(engine, table_name, column):
    column_name = column.compile(dialect=engine.dialect)
    column_type = column.type.compile(engine.dialect)
    engine.execute('ALTER TABLE %s ADD COLUMN %s %s' % (table_name, column_name, column_type))

column = Column('new_column_name', String(100), primary_key=True)
add_column(engine, table_name, column)

不过,我不知道如何将primary_key=True 插入到原始 SQL 请求中。

【讨论】:

  • column.type.compile(engine.dialect) 是我想要的。在其他任何地方都找不到。
  • 已经七年多了,把这个答案扩展了一下……stackoverflow.com/a/65874034/2558739
【解决方案2】:

这称为数据库迁移(SQLAlchemy 不支持开箱即用的迁移)。您可以考虑使用sqlalchemy-migrate 在这些情况下提供帮助,或者您可以通过您选择的数据库的命令行实用程序直接使用ALTER TABLE

【讨论】:

  • 所以我必须迁移整个数据库只是为了添加一列?这听起来不好玩。谢谢!
  • 那么对于 ALTER TABLE,我可以通过 SQLAlchemy 做到这一点(即它是否支持直接编写 SQLite)?但我会继续迁移
  • 不,SQLAlchemy 不支持修改数据库表,只支持创建。您必须通过 sqlite3 执行 ALTER
  • @TheGrimmScientist 好吧,我明白你的意思,但是如果我已经在同一个厨房里泡过茶,听起来我们必须买一个新厨房来煮咖啡吗?
  • 我可以访问只访问数据库并执行SQL命令来更改表吗?
【解决方案3】:

请参阅 SQLAlchemy 文档的这一部分:http://docs.sqlalchemy.org/en/latest/core/metadata.html#altering-schemas-through-migrations

Alembic 是提供此类功能的最新软件,由与 SQLAlchemy 同一作者制作。

【讨论】:

  • Flask 扩展 Flask-Migrate 也在使用 Alembic,我觉得应该是一个不错的解决方案。
【解决方案4】:

我有一个用 sqlite3 构建的名为“ncaaf.db”的数据库和一个名为“games”的表。所以我会 CD 到我的 linux 命令提示符下的同一目录并执行

sqlite3 ncaaf.db
alter table games add column q4 type float

仅此而已!只需确保更新 sqlalchemy 代码中的定义即可。

【讨论】:

  • 这个答案很简单。它需要更多的选票。只要确保你有 sqlite 命令行 shell。 sqlite.org/download.html.
  • 第二行对我有用:ALTER TABLE games ADD COLUMN q4 FLOAT;
【解决方案5】:

我遇到了同样的问题,最后我只是用原始 sql 编写了自己的函数。如果您使用的是 SQLITE3,这可能很有用。

然后,如果您同时将该列添加到您的类定义中,它似乎可以解决问题。

import sqlite3 

def add_column(database_name, table_name, column_name, data_type):

  connection = sqlite3.connect(database_name)
  cursor = connection.cursor()

  if data_type == "Integer":
    data_type_formatted = "INTEGER"
  elif data_type == "String":
    data_type_formatted = "VARCHAR(100)"

  base_command = ("ALTER TABLE '{table_name}' ADD column '{column_name}' '{data_type}'")
  sql_command = base_command.format(table_name=table_name, column_name=column_name, data_type=data_type_formatted)

  cursor.execute(sql_command)
  connection.commit()
  connection.close()

【讨论】:

    【解决方案6】:
    from sqlalchemy import create_engine
    engine = create_engine('sqlite:///db.sqlite3')
    
    engine.execute('alter table table_name add column column_name String')
    

    【讨论】:

      【解决方案7】:

      只是继续chasmani提出的简单方法,改进不大

      '''
      # simple migration
      # columns to add: 
      # last_status_change = Column(BigInteger, default=None) 
      # last_complete_phase = Column(String, default=None)  
      # complete_percentage = Column(DECIMAL, default=0.0)
      '''
      
      import sqlite3
      
      from config import APP_STATUS_DB
      from sqlalchemy import types
      
      
      def add_column(database_name: str, table_name: str, column_name: str, data_type: types, default=None):
          ret = False
      
          if default is not None:
              try:
                  float(default)
                  ddl = ("ALTER TABLE '{table_name}' ADD column '{column_name}' '{data_type}' DEFAULT {default}")
              except:
                  ddl = ("ALTER TABLE '{table_name}' ADD column '{column_name}' '{data_type}' DEFAULT '{default}'")
          else:
              ddl = ("ALTER TABLE '{table_name}' ADD column '{column_name}' '{data_type}'")
      
          sql_command = ddl.format(table_name=table_name, column_name=column_name, data_type=data_type.__name__,
                                   default=default)
          try:
              connection = sqlite3.connect(database_name)
              cursor = connection.cursor()
              cursor.execute(sql_command)
              connection.commit()
              connection.close()
              ret = True
          except Exception as e:
              print(e)
              ret = False
          return ret
      
      
      add_column(APP_STATUS_DB, 'procedures', 'last_status_change', types.BigInteger)
      add_column(APP_STATUS_DB, 'procedures', 'last_complete_phase', types.String)
      add_column(APP_STATUS_DB, 'procedures', 'complete_percentage', types.DECIMAL, 0.0)
      

      【讨论】:

        【解决方案8】:

        我最近遇到了同样的问题,所以我在之前的回答中从 AlexP 那里得到了一点。问题在于将新列放入我程序的元数据中。使用 sqlAlchemy 的 append_column 功能会产生一些意想不到的下游影响('str' 对象没有属性 'dialect impl')。我通过添加带有 DDL(在本例中为 MySQL 数据库)的列,然后将表从数据库反映到我的元数据中来纠正此问题。

        代码大致如下(稍微修改了我所拥有的,以将其减少到最低限度。对于任何错误,我深表歉意 - 如果有,它们应该是轻微的)......

        try:
            # Use back quotes as a protection against SQL Injection Attacks. Can we do more?
            common.qry_engine.execute('ALTER TABLE %s ADD COLUMN %s %s' %
                                      ('`' + self.tbl.schema + '`.`' + self.tbl.name + '`',
                                       '`' + self.outputs[new_col] + '`', 'VARCHAR(50)'))
        except exc.SQLAlchemyError as msg:
            raise GRError(desc='Unable to physically add derived column to table. Contact support.',
                          data=str(self.outputs), other_info=str(msg))
        
        try:    # Refresh the metadata to show the new column
            self.tbl = sqlalchemy.Table(self.tbl.name, self.tbl.metadata, extend_existing=True, autoload=True)
        except exc.SQLAlchemyError as msg:
            raise GRError(desc='Unable to establish metadata for new column. Contact support.',
                          data=str(self.outputs), other_info=str(msg))
        

        【讨论】:

          【解决方案9】:

          是的,你可以 安装 sqlalchemy-migrate (pip install sqlalchemy-migrate) 并在脚本中使用它来调用 Table and Column create() 方法:

          from sqlalchemy import String, MetaData, create_engine
          from migrate.versioning.schema import Table, Column
          
          db_engine =  create_engine(app.config.get('SQLALCHEMY_DATABASE_URI'))
          db_meta = MetaData(bind=db_engine)
          
          table = Table('tabel_name' , db_meta)
          col = Column('new_column_name', String(20), default='foo')
              col.create(table)
          

          【讨论】:

            【解决方案10】:

            “手动”添加列(不使用 python 或 SQLAlchemy)也许是最简单的?

            【讨论】:

              【解决方案11】:

              这里也有同样的问题。我要做的是遍历数据库并将每个条目添加到具有额外列的新数据库中,然后删除旧数据库并将新数据库重命名为这个。

              【讨论】:

                猜你喜欢
                • 2019-08-11
                • 2014-07-31
                • 2020-08-04
                • 1970-01-01
                • 2013-08-01
                • 1970-01-01
                • 1970-01-01
                • 2022-01-11
                相关资源
                最近更新 更多