SQLAlchemy的。创建共享枚举的表

时间:2016-08-18 17:08:12

标签: python postgresql enums sqlalchemy

模型FacebookPost和TwitterPost共享一个名为类型的枚举。在创建facebook_posts表时正确创建此枚举,但在尝试创建twitter_posts表时,尝试重新创建此类型会导致错误。

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) type "types" already exists
 [SQL: "CREATE TYPE types AS ENUM ('Video', 'GIF', 'Scratch Reel', 'Card', 'Video Card', 'Text', 'Photo', 'Shared Article', 'Reply', 'Canvas', 'Carousel', 'Video Carousel', 'Link', 'Status')"]

这就是我创建数据库的方式。我无法使用Base.metadata.create_all,因为我需要明确表示创建的表

Engine = create_engine(db_url, echo=False)
Campaign.__table__.create(Engine)
SubCampaign.__table__.create(Engine)
Creative.__table__.create(Engine)
Hashtag.__table__.create(Engine)
FacebookPost.__table__.create(Engine)
TwitterPost.__table__.create(Engine)

我以这种方式创建枚举:

from sqlalchemy import Enum
types = ('Video', 'GIF', 'Scratch Reel', 'Card', 'Video Card',
         'Text', 'Photo', 'Shared Article', 'Reply', 'Canvas',
         'Carousel', 'Video Carousel', 'Link', 'Status')
goals = ('CTR', 'ER', 'Awareness', 'CPGA')
sources = ('Facebook', 'Twitter', 'Instagram', 'Tumblr')

vars_ = locals().copy()
for k, v in vars_.items():
    if isinstance(v, tuple):
        locals()[k] = Enum(*v, name=k)

3 个答案:

答案 0 :(得分:1)

通用Enum类不提供对发出CREATE TYPE语句的任何控制。但是PostgreSQL特定的替代方法ENUM具有参数create_type,可用于禁用它:

from sqlalchemy.dialects.postgresql import ENUM


class TwitterPost(Base):
    ...
    type = Column("type", ENUM(*types, name="post_type", create_type=False))
    ...

答案 1 :(得分:1)

我在Alembic中遇到了类似的问题,并使用了解决方法。

第一个示例不起作用。 SQLAlchemy在调用create时创建枚举,但是在创建表时尝试再次创建该枚举,从而导致错误。

NEW_ENUM = sa.Enum(
    "A",
    "B",
    "C",
    name="my_enum",
    schema="my_schema"
)

NEW_ENUM.create(op.get_bind())

op.create_table(
    "table1",
    sa.MetaData(),
    sa.Column("id", sa.Integer, primary_key=True),
    sa.Column("column1", sa.String),
    sa.Column("column2", NEW_ENUM),
    schema="my_schema",
)

op.create_table(
    "table2",
    sa.MetaData(),
    sa.Column("id", sa.Integer, primary_key=True),
    sa.Column("column1", sa.Integer),
    sa.Column("column2", NEW_ENUM),
    schema="my_schema",
)

但是,创建没有枚举列的表并在之后添加它们是可行的。枚举在数据库上创建一次(在我的情况下为Postgres),并用于添加列中的两个表:

NEW_ENUM = sa.Enum(
    "A",
    "B",
    "C",
    name="my_enum",
    schema="my_schema"
)

NEW_ENUM.create(op.get_bind())

op.create_table(
    "table1",
    sa.MetaData(),
    sa.Column("id", sa.Integer, primary_key=True),
    sa.Column("column1", sa.String),
    schema="my_schema",
)

op.add_column("table1", sa.Column("column2", NEW_ENUM), schema="my_schema")

op.create_table(
    "table2",
    sa.MetaData(),
    sa.Column("id", sa.Integer, primary_key=True),
    sa.Column("column1", sa.Integer),
    schema="my_schema",
)

op.add_column("table2", sa.Column("column2", NEW_ENUM), schema="my_schema")

答案 2 :(得分:0)

对于使用 Alembic 并遇到此问题的任何人。

还有一个 postgresql.ENUM kwarg 表示 sa.Column('ActionType', postgresql.ENUM('Primary', 'Secondary', name='actiontype', create_type=False), nullable=True), 。用于在 alembic 迁移脚本中设置枚举类型列的架构。

这是我的列定义的样子。 (使用现有的枚举)

SQLAlchemy==1.1.1

现在将使用现有枚举作为新列,而不创建新列。

我在我的需求文件中使用了 alembic==0.8.8movePlayer(Vector3 direction)

我给出了类似的答案here