2010-01-20 34 views

Trả lời

5

SQLAlchemy chính nó không hỗ trợ cập nhật tự động lược đồ, nhưng có một công cụ bên thứ ba SQLAlchemy Migrate để tự động di chuyển. Xem qua "Database schema versioning workflow" chapter để xem cách hoạt động.

+0

xin cảm ơn, đã suy nghĩ nhiều ... – jagguli

+0

Tôi có thể yêu cầu liên kết mới không? Cái đó dường như đã chết. Cảm ơn trước. – Nonsingular

9

Đôi khi Di chuyển quá nhiều công việc - bạn chỉ muốn cột tự động được thêm khi bạn chạy mã đã thay đổi. Vì vậy, đây là một chức năng mà làm điều đó.

Hãy cẩn thận: nó chọc xung quanh trong nội bộ SQLAlchemy và có xu hướng yêu cầu thay đổi nhỏ mỗi khi SQLAlchemy trải qua một phiên bản chính. (Có lẽ có một cách tốt hơn để làm điều này - tôi không phải là một chuyên gia về SQLAlchemy). Nó cũng không xử lý các ràng buộc.

import logging 
import re 

import sqlalchemy 
from sqlalchemy import MetaData, Table, exceptions 
import sqlalchemy.engine.ddl 

_new_sa_ddl = sqlalchemy.__version__.startswith('0.7') 


def create_and_upgrade(engine, metadata): 
    """For each table in metadata, if it is not in the database then create it. 
    If it is in the database then add any missing columns and warn about any columns 
    whose spec has changed""" 
    db_metadata = MetaData() 
    db_metadata.bind = engine 

    for model_table in metadata.sorted_tables: 
     try: 
      db_table = Table(model_table.name, db_metadata, autoload=True) 
     except exceptions.NoSuchTableError: 
      logging.info('Creating table %s' % model_table.name) 
      model_table.create(bind=engine) 
     else: 
      if _new_sa_ddl: 
       ddl_c = engine.dialect.ddl_compiler(engine.dialect, None) 
      else: 
       # 0.6 
       ddl_c = engine.dialect.ddl_compiler(engine.dialect, db_table) 
      # else: 
       # 0.5 
       # ddl_c = engine.dialect.schemagenerator(engine.dialect, engine.contextual_connect()) 

      logging.debug('Table %s already exists. Checking for missing columns' % model_table.name) 

      model_columns = _column_names(model_table) 
      db_columns = _column_names(db_table) 

      to_create = model_columns - db_columns 
      to_remove = db_columns - model_columns 
      to_check = db_columns.intersection(model_columns) 

      for c in to_create: 
       model_column = getattr(model_table.c, c) 
       logging.info('Adding column %s.%s' % (model_table.name, model_column.name)) 
       assert not model_column.constraints, \ 
        'Arrrgh! I cannot automatically add columns with constraints to the database'\ 
         'Please consider fixing me if you care!' 
       model_col_spec = ddl_c.get_column_specification(model_column) 
       sql = 'ALTER TABLE %s ADD %s' % (model_table.name, model_col_spec) 
       engine.execute(sql) 

      # It's difficult to reliably determine if the model has changed 
      # a column definition. E.g. the default precision of columns 
      # is None, which means the database decides. Therefore when I look at the model 
      # it may give the SQL for the column as INTEGER but when I look at the database 
      # I have a definite precision, therefore the returned type is INTEGER(11) 

      for c in to_check: 
       model_column = model_table.c[c] 
       db_column = db_table.c[c] 
       x = model_column == db_column 

       logging.debug('Checking column %s.%s' % (model_table.name, model_column.name)) 
       model_col_spec = ddl_c.get_column_specification(model_column) 
       db_col_spec = ddl_c.get_column_specification(db_column) 

       model_col_spec = re.sub('[(][\d ,]+[)]', '', model_col_spec) 
       db_col_spec = re.sub('[(][\d ,]+[)]', '', db_col_spec) 
       db_col_spec = db_col_spec.replace('DECIMAL', 'NUMERIC') 
       db_col_spec = db_col_spec.replace('TINYINT', 'BOOL') 

       if model_col_spec != db_col_spec: 
        logging.warning('Column %s.%s has specification %r in the model but %r in the database' % 
             (model_table.name, model_column.name, model_col_spec, db_col_spec)) 

       if model_column.constraints or db_column.constraints: 
        # TODO, check constraints 
        logging.debug('Column constraints not checked. I am too dumb') 

      for c in to_remove: 
       model_column = getattr(db_table.c, c) 
       logging.warning('Column %s.%s in the database is not in the model' % (model_table.name, model_column.name)) 


def _column_names(table): 
    # Autoloaded columns return unicode column names - make sure we treat all are equal 
    return set((unicode(i.name) for i in table.c)) 
+0

Cảm ơn bạn rất nhiều! Chính xác những gì tôi đang tìm kiếm. – kay

0
# database.py has definition for engine. 
# from sqlalchemy import create_engine 
# engine = create_engine('mysql://......', convert_unicode=True) 

from database import engine 
from sqlalchemy import DDL 

add_column = DDL('ALTER TABLE USERS ADD COLUMN city VARCHAR(60) AFTER email') 
engine.execute(add_column) 
Các vấn đề liên quan