2013-06-27 4 views
0

Я пишу скрипт импорта/экспорта sqlalchemy с использованием дампов и загрузок сериализатора. Экспорт работает, но у меня проблемы с импортом, главным образом из-за проблем с внешним ключом. Я использую sorted_tables, чтобы получить список таблиц, отсортированных по зависимостям, и это гарантирует, что у меня не будет проблем с внешними ключами перекрестных таблиц, но есть ли что-то похожее на обработку внутренних внешних ключей (таблица, указывающая на себя)?sqlalchemy import export failing on IntegrityError

Я в основном думал о 2 возможном решении:

  1. найти способ сортировки строк на основе зависимости
  2. Отключить все ограничения -> вставить данные -> включить все ограничения снова

, но я не знаю, как сделать это правильно ...

пример таблицы:

class Employee(Base): 
    __tablename__ = "t_employee" 

    id = sa.Column(Identifier, sa.Sequence('%s_id_seq' % __tablename__), primary_key=True, nullable=False) 
    first_name = sa.Column(sa.String(30)) 
    last_name = sa.Column(sa.String(30)) 
    manager_id = sa.Column(Identifier, sa.ForeignKey("t_employee.id", ondelete='SET NULL')) 

и вот мой сценарий:

def export_db(tar_file): 
    print "Exporting Database. This may take some time. Please wait ..." 

    Base.metadata.create_all(engine) 
    tables = Base.metadata.tables 

    with tarfile.open(tar_file, "w:bz2") as tar: 
     for tbl in tables: 
      print "Exporting table %s ..." % tbl 
      table_dump = dumps(engine.execute(tables[tbl].select()).fetchall()) 

      ti = tarfile.TarInfo(tbl) 
      ti.size = len(table_dump) 
      tar.addfile(ti, StringIO(table_dump)) 

    print "Database exported! Exiting!" 

    exit(0) 

def import_db(tar_file): 
    print "Importing to Database. This may take some time. Please wait ..." 

    print "Dropping all tables ..." 
    Base.metadata.drop_all(engine) 

    print "Creating all tables ..." 
    Base.metadata.create_all(engine) 
    tables = Base.metadata.sorted_tables 

    with tarfile.open(tar_file, "r:bz2") as tar: 
     for tbl in tables: 
      try: 
       entry = tar.getmember(tbl.name) 
       print "Importing table %s ..." % entry.name 
       fileobj = tar.extractfile(entry) 
       table_dump = loads(fileobj.read(), Base.metadata, db) 
       for data in table_dump: 
        db.execute(tbl.insert(), strip_unicode(dict(**data))) 
      except: 
       traceback.print_exc(file=sys.stdout) 
       exit(0) 
     db.commit() 

    print "Database imported! Exiting!" 

    exit(0) 

ответ

3

Для массовых свалок, стандартный метод отключить ограничения, сделать импорт, а затем снова включите их. Вы также получите гораздо более высокую производительность на вставках.

+0

Это здорово, но как это сделать в sqlalchemy? любой простой способ? – Ofir

+0

, вам нужно исправить соответствующие инструкции SQL, которые достигают этого. Например, [этот ответ] (http://stackoverflow.com/a/2681413/34549) иллюстрирует, что на Postgresql вы можете использовать команду «SET CONSTRAINTS ALL DEFERRED». Другой подход заключается в том, чтобы использовать SQLAlchemy для отражения всех ограничений, затем DROP их явно, а затем воссоздать их - вы можете снять некоторые идеи из рецепта [здесь] (http://www.sqlalchemy.org/trac/wiki/UsageRecipes/DropEverything), что может помочь в этом. – zzzeek

+0

спасибо, это похоже на возможное направление, хотя мне кажется странным, что это самый простой способ. Я пойду с таким подходом, если не найду ничего проще. – Ofir