首页 > 解决方案 > 无法从 SQLAlchemy 中的 psql-> sqlite3 create_all()

问题描述

我正在尝试将 PostgressSQL -> 转储到 -> SQLite3 及其所有数据。

主要思想是创建两个引擎,一个用于 PSQL,第二个用于 sqlite3。然后我reflect在 sqlite 引擎上的 psql 引擎 - 并运行create_all()但随后我收到以下错误

2019-07-18 11:41:47,660 INFO sqlalchemy.engine.base.Engine ()
2019-07-18 11:41:47,660 INFO sqlalchemy.engine.base.Engine ROLLBACK
Traceback (most recent call last):
    ... etc ...
sqlalchemy.exc.OperationalError: (pysqlite2.dbapi2.OperationalError) near "(": syntax error [SQL: u"\nCREATE TABLE table1 (\n\tcolumn_id INTEGER DEFAULT nextval('table1_id_seq'::regclass) NOT NULL, \n\t
(Background on this error at: http://sqlalche.me/e/e3q8)

这很有趣,因为 SQLAlchemy 生成了CREATE TABLE- 确实如此。create table问题是它何时执行sqlite3然后sqlite3将错误返回给 SQLAlchemy - 它不了解以下内容nextval::是:

column_id INTEGER DEFAULT nextval('table1_id_seq'::regclass) NOT NULL,
column_name VARCHAR(15) DEFAULT 'no-name'::character varying,

就我个人而言,我什至不需要这些——因为 sqlite 将用作快照数据库,但我怎么能忽略它呢?或调整?

编辑 1- 使用特定型号

如果在代码中我写了这样的东西

class Table1(Base):
    __table__ = Table('table1',
                    Base.metadata,
                    Column('column_id', Integer, primary_key=True),
                    Column('column_name', Text, default='no-name'),
                    autoload=True)

工作示例 - 但我正在尝试做同样的事情class Table1

from sqlalchemy import create_engine
from sqlalchemy import Table, Column, Integer, Text
from sqlalchemy.ext.declarative import declarative_base


def review_md_tables(metadata):

    if not metadata.sorted_tables:
        print "-> Tables not found"
        return

    for Table in metadata.sorted_tables:
        print "->", Table.name


print "PSQL database"
psql_url = "postgress://..."
psql_engine = create_engine(psql_url, echo=False)
psql_base = declarative_base(bind=psql_engine)
review_md_tables(psql_base.metadata)

class Table1(psql_base):
    __table__ = Table('table1',
                    pql_base.metadata,
                    Column('column_id', Integer, primary_key=True),
                    Column('column_name', Text, default='no-name'),
                    autoload=True)

review_md_tables(psql_base.metadata)

sqlite_url = "sqlite:////tmp/db.sqlite"
sqlite_enging = create_engine(sqlite_url, echo=False)

# Duplicate PSQL tables -> SQLite
psql_base.metadata.create_all(sqlite_enging)

问题是,我不想开始为数据库中的每个表编写类模型......有什么想法吗?

标签: pythonsqlalchemy

解决方案


除非有人有更好的主意,否则这是我迄今为止找到的解决方案 - 是server_default从这些列中一一删除(我们可以使用defaultSQLAlchemy 默认定义..

def remove_defaults_from_tables(metadata):
    for Table in metadata.sorted_tables:
        print "--> Adjusting table: ", Table.name

        # Fixing PSQL unsupported DEFAULT & serial columns
        # https://github.com/sqlalchemy/sqlalchemy/issues/525
        # https://github.com/sqlalchemy/sqlalchemy/issues/1565
        if Table.name in ["table1", "table2"]:
            Table.c.id.server_default = None

所以这个函数应该在填充完所有之后metadata使用Tables

# This doesn't require pre-defined Models - 
# BUT they will also load those special PSQL variables which SQLAlchemy 
# can't determine later during the `create_all`
Base.metadata.reflect(bind=my_psql_engine, only=["table1", "table2"])
remove_defaults_from_tables(Base.metadata)

推荐阅读