2013-01-19 29 views
15

後,我有一個燒瓶SQLAlchemy的模型:添加索引到SQLAlchemy的模型創建表

class MyModel(db.Model): 
__tablename__ = 'targets' 
id = db.Column(db.Integer, primary_key=True) 
url = db.Column(db.String(2048)) 

表已經創建,並且在使用中。我想創建url屬性的索引,所以我通過指數=真到它:

url = db.Column(db.String(2048), index=True) 

我怎樣才能讓這個指數生效,而無需刪除並重新創建表?

回答

2

請注意,這是不正確的,過於複雜的答案

正確的方法是使用index.create因爲有人說here


首先確保您擁有數據庫的最新快照,並且能夠從此快照中恢復數據庫。

對於中型和大型項目(可能需要同時支持多個版本並安裝在多個環境中的項目),有一個特殊過程,它是數據庫管理生命週期的一部分,稱爲「數據庫遷移」。數據庫遷移包括對現有模式的更改。 SQLAlchemy不支持遷移開箱即用。

有兩種可用的SQLAlchemy兼容的數據庫遷移工具:

查看更多信息,並鏈接到SQLAlchemy的文檔頁面這些工具:Altering Schemas through Migrations

但是,如果您正在處理小型項目,我會建議從數據庫命令行實用程序或通過python腳本中的connection.execute()手動運行ALTER TABLE DDL查詢。

在我現在正在工作的生產應用程序中,我們只支持一個最新版本的應用程序。對於每一個數據庫模式的變化,我們做以下步驟:

  • 使生產數據庫
  • 負載此快照發展環境的快照
  • 更新SQLAlchemy的數據模型模塊
  • 準備和運行alter table查詢並保存此查詢後
  • 對代碼
  • 運行測試的開發環境等相關的變化
  • 最新版本的代碼部署到生產環境
  • 不改變生產

而且我使用下面的技巧,用於生成創建表/索引的查詢表: 我點我的應用程序,以全新的數據庫,使記錄sqlalchemy查詢並運行metadata.create_all() - 因此在日誌(或標準輸出)中,我看到由sqlalchemy生成的創建查詢

根據您使用的索引創建查詢的數據庫系統會有所不同。 通用查詢應該是這樣的:

create index targets_i on targets(url); 
+0

對不起,這個回答是錯誤的。 ALTER TABLE不用於索引。 SQLAlchemy的支持「CREATE INDEX」非常直接地使用'Index.create()',以及用'CreateIndex' DDL構建更復雜的腳本的情況。沒有必要抓住「create_all()」輸出或類似的東西。 – zzzeek

+0

謝謝指出。我同意 - 我描述瞭如何實施和支持有問題的方法。並且完全忘記了簡單快捷的'index.create'。 – vvladymyrov

6
+8

這個答案不知道從原始問題的代碼中從哪裏獲取這個索引對象。通過文檔爬行發現這是艱苦的,老老實實勉強幫助的,因爲他們不使用聲明API(這是在原來的問題正在使用的)碰。對於像我一樣困惑的其他人,不想抓取文檔和源代碼,請參閱我的下面的答案。 – brthornbury

15

目前頂級的答案沒有幫助我,當我降落在這裏。閱讀文檔(和源代碼)後,我發現這個工作,希望它有幫助。

給出原始問題的模型類。

class MyModel(db.Model): 
    __tablename__ = 'targets' 
    id = db.Column(db.Integer, primary_key=True) 
    url = db.Column(db.String(2048)) 

你不能只是增加index=True因爲即使你叫db.Model.metadata.create_all()該索引將不會在已創建的表中創建。

相反,您需要創建一個獨立的Index對象,然後創建它。它會是這個樣子:

class MyModel(db.Model): 
    __tablename__ = 'targets' 
    id = db.Column(db.Integer, primary_key=True) 
    url = db.Column(db.String(2048)) 

mymodel_url_index = Index('mymodel_url_idx', MyModel.url) 

if __name__ == '__main__': 
    mymodel_url_index.create(bind=engine) 

現在在哪兒engine來自將達到你的SQLAlchemy的配置,但是這個代碼應該傳達需要採取什麼措施的要點。

-1

我不確定這是否符合最佳做法,但我發現Alembic會通知我__table_args__中的索引,但實際上在遷移期間並不適合我。我製作了這個小腳本,可以生成在__table_args__屬性中找到的新索引。如上所述,它使用Index.create(),但如果它們不存在,將生成新的索引。

def create_indexes(db, drop_index=False): 
    """ 
    Creates all indexes on models in project if they do not exists already. Assumes all models 
    inherit from RequiredFields class, otherwise will need to adjust search for subclasses. If the index 
    exists SQLAlchemy throws an error and we assume everything is ok. 
    :param db: The app db object, acts as the engine param for the Index.create() 
    :param drop_index: specifies whether the indexes should be dropped or created 
    :return: 
    """ 
    from application.base_models import RequiredFields 
    from sqlalchemy import Index 
    from sqlalchemy.exc import ProgrammingError 
    for klass in RequiredFields.__subclasses__(): 
     if hasattr(klass, '__table_args__'): 
      for item in getattr(klass, '__table_args__'): 
       if isinstance(item, Index): 
        try: 
         if not drop_index: 
          item.create(db.engine) 
         else: 
          item.drop(db.engine) 
        except ProgrammingError: # If index exists, creation fails on error 
         pass 
    return 

這裏是表示索引的示例類。

class MyModel(RequiredFields): 

    __table_args__ = (
     db.Index(...), 
     db.Index(...), 
    ) 
-3

使用flask-移液器。它很酷。 在添加索引,就使用這個命令:

python manage.py db migrate 

一切正常

0

如果你使用的蒸餾器,你可以創建一個遷移要做到這一點,並避免將其添加到模型中全部:

def upgrade(): 
    # ### commands auto generated by Alembic - please adjust! ### 
    op.create_index('table1_id', 'table1', ['id'], unique=True) 
    op.create_index('table2_id', 'table2', ['id'], unique=True) 
    # ### end Alembic commands ### 

def downgrade(): 
    # ### commands auto generated by Alembic - please adjust! ### 
    op.drop_index('table1_id', table_name='table1') 
    op.drop_index('table2_id', table_name='table2') 
    # ### end Alembic commands ### 
相關問題