如何在 SQLAlchemy 1.2.7 中创建没有定义类的新表

Posted

技术标签:

【中文标题】如何在 SQLAlchemy 1.2.7 中创建没有定义类的新表【英文标题】:How to Create New Tables without Defined Classes in SQLAlchemy 1.2.7 【发布时间】:2018-10-08 20:09:39 【问题描述】:

我正在使用 SQLAlchemy 的声明式 API 为我的应用程序构建模型和表。

但是,由于错误NoReferencedTableError: Foreign key associated with column 'org_prediction.company_id' could not find table 'organization' with which to generate a foreign key to target column 'id',我无法使用Base.metadata.create_all(engine) 命令在我的数据库中构建新表

发生这种情况的原因是我试图为 ForeignKey 引用的类 Organization 不存在于我的 models.py 文件中。所以,当我打电话给Base.metadata.create_all(engine) 时,SQLAlchemy 会窒息,因为 Base 中不存在类 Organization...

我已尝试反映我的数据库,它将返回存在的组织表,但在我的 models.py 文件中没有为它编写相应的类。但是当我反映数据库表并尝试在组织之上创建我的新依赖类时,我收到如下错误:InvalidRequestError: Table 'user' is already defined for this MetaData instance. Specify 'extend_existing=True' to redefine options and columns on an existing Table object.,这是因为反射的 MetaData 和我的用户的 models.py 类重叠,而 SQLAlchemy 是不知道该怎么办。

但是我应该在哪里应用extend_existing=True?我没有要将此参数传递到的表对象。当我的 FK 依赖表在我的 models.py 文件中不存在时,如何创建我的 FK 依赖表?或者我怎样才能反映我现有的表,但只追加或更新数据库中尚不存在的类?

models.py

from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(String(50))

class OrgPrediction(Base):
    __tablename__ = 'org_prediction'
    id = Column(Integer, primary_key=True)
    company_id = Column(String(255), ForeignKey('organization.id'), nullable=True)
    prediction = Column(String(255)
Base.metadata.create_all(engine)

NoReferencedTableError: 与列 'org_prediction.company_id' 关联的外键找不到表 'organization' 来生成目标列 'id' 的外键

mysql

mysql> desc organization;
+-----------------------+------------+------+-----+---------+-------+
| Field                 | Type       | Null | Key | Default | Extra |
+-----------------------+------------+------+-----+---------+-------+
| id                 | bigint(20) | YES  | MUL | NULL    |       |


mysql> show tables;
+-------------------------+
| Tables_in_database |
+-------------------------+
| organization            |
| user                    |
| user_email              |

在反射的情况下models.py文件:

from sqlalchemy.ext.automap import automap_base
from sqlalchemy import create_engine

Base = automap_base()
Base.prepare(engine, reflect=True)

class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(String(50))

class OrgPrediction(Base):
    __tablename__ = 'org_prediction'
    id = Column(Integer, primary_key=True)
    company_id = Column(String(255), ForeignKey('organization.id'), nullable=True)

Base.metadata.create_all(engine)

InvalidRequestError:已经为此 MetaData 实例定义了表“用户”。指定 'extend_existing=True' 以重新定义现有 Table 对象上的选项和列。

【问题讨论】:

【参考方案1】:

有一种方法可以做到这一点,它涉及在添加外键依赖表之前使用 Base.metadata.reflect(only=['table_name']) 功能。我测试的最终代码:

Base = declarative_base()
class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)
    username = Column(String(50))

#see what tables exist in metadata right now
In [85]: Base.metadata.sorted_tables
Out[85]: [Table('user', MetaData(bind=None), Column('id', Integer(), table=<user>, primary_key=True, nullable=False), Column('username', String(length=50), table=<user>), schema=None)]

# this will add the organization table/class to the Base's Metadata. This also needs to happen before the Foreign Key reference in OrgPrediction class.
Base.metadata.reflect(bind=engine, only=['organization'])

# now this class' foreign key will reference organization.id which exists in Base metadata.
class OrgPrediction(Base):
    __tablename__ = 'org_prediction'
    id = Column(Integer, primary_key=True)
    company_id = Column(String(255), ForeignKey('organization.id'), nullable=True)
    prediction = Column(String(255))

# this should pass because the foreign key constraint is met.
Base.metadata.create_all(engine)

【讨论】:

以上是关于如何在 SQLAlchemy 1.2.7 中创建没有定义类的新表的主要内容,如果未能解决你的问题,请参考以下文章

如何在 python 中使用 sqlalchemy 在查询中创建 sql server 表变量

使用SQLAlchemy,如何在类中创建一个字段,该类是所述类的其他实例的列表? [重复]

SqlAlchemy 将新字段添加到类并在表中创建相应的列

在 SQLAlchemy 中创建类似集合的映射属性

使用 PostgreSQL 在 SQLAlchemy 测试中创建数据库

在 SQLAlchemy 中创建混合属性的自定义元类