2012-05-11 59 views
3

我在生產中運行mysql,但想在內存數據庫的sqlite中運行一個簡單的測試。如何動態更改SQLAlchemy聲明模型的列類型?

傳統mysql數據庫具有表格,其中的列是特定於mysql的類型的列,這些列是在聲明性模型(declarative_base的子類)中聲明的。我想運行一些簡單的測試而不用去mysql,所以需要換出模型的列。

我該怎麼做?我試着寫一個補丁/ unpatcher換出在我的模型,但是當我運行一些測試,我得到

OperationalError: (OperationalError) near ")": syntax error u'\nCREATE TABLE my_table (\n)\n\n'() 

這讓我覺得我不是正確的修補列。

有誰知道我該怎麼做?我究竟做錯了什麼?

目前,我創建新列並將全新的表格對象附加到__table__並保存舊錶格。

數據庫已創建,create_all()is和convert_columns在setUp中運行。 drop_all()和revert_columns被拆卸過程中我的測試

mysql_sqlite_mapping = {INTEGER: Integer, 
         MEDIUMINT: Integer, 
         TEXT: text}  

def convert_columns(self, my_class, mapping): 
    for column in my_class.__table__.columns: 
     if type(column.type) in mapping: 
      replacement_col = Column(column.name, 
            mapping[type(column.type)], 
            primary_key=column.primary_key, 
            nullable=column.nullable, 
            key=column.key, 
            unique=column.unique) 

      converted_columns.append(replacement_col) 

    self.registry[my_class] = my_class.__table__ 

    my_class.__table__.metadata.remove(my_class.__table__) 
    my_class.__table__ = Table(my_class.__table__.name, 
           my_class.__table__.metadata) 

    for column in converted_columns: 
     my_class.__table__.append_column(column) 

    return my_class 

def revert_columns(self, my_class): 
    saved_table = self.registry[my_class] 

    metadata = my_class.__table__.metadata 
    my_class.__table__.metadata.remove(my_class.__table__) 

    model_class.__table__ = Table(saved_table.name, 
            metadata) 

    for column in saved_table.columns: 
     column.table = None 
     my_class.__table__.append_column(column) 

    self.registry.pop(my_class) 

回答

3

運行我希望下面的可以幫助你處理這些類型的修改的更好方式。但是您的錯誤很奇怪,因爲它在CREATE TABLE條款中沒有列,所以我不認爲這是您的問題的直接答案/解決方案。

反正,不是完全替換表和列,爲什麼不嘗試使用Custom SQL Constructs and Compilation Extension/Dialect-specific compilation rules。請參閱示例代碼,它應該爲sqlite生成適當的SQL語句而不更改表定義:

from sqlalchemy.ext.compiler import compiles 
from sqlalchemy.dialects.mysql import MEDIUMINT, INTEGER, TEXT 

@compiles(MEDIUMINT, 'sqlite') 
def compile_MEDIUMINT(element, compiler, **kw): 
    """ Handles mysql MEDIUMINT datatype as Integer in sqlite. """ 
    return compiler.visit_integer(element, **kw) 

@compiles(INTEGER, 'sqlite') 
def compile_INTEGER(element, compiler, **kw): 
    """ Handles mysql INTEGER datatype as Integer in sqlite. """ 
    return compiler.visit_integer(element, **kw) 


@compiles(TEXT, 'sqlite') 
def compile_TEXT(element, compiler, **kw): 
    """ Handles mysql TEXT datatype as text in sqlite. """ 
    return compiler.visit_text(element, **kw) 
+0

感謝您的回覆,但是如何將此與聲明一起使用?相反,我是否在執行@compiles?我想保持這種模式,因爲它僅用於運行測試。 – sasker

+0

我只需在我的測試模塊中導入上面的代碼? – sasker

+0

是的,這應該足以生成正確的'DDL'語句。 – van