【问题标题】:SQLAlchemy. Creating tables that share enumSQL炼金术。创建共享枚举的表
【发布时间】:2016-12-25 17:16:21
【问题描述】:

模型FacebookPost和TwitterPost共享一个枚举类型叫做。创建facebook_posts表时,但试图创建twitter_posts表时,是重新创建这种类型的导致错误的尝试该枚举正确创建。 P>

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,因为我需要明确的是创造了什么表方面 P>

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)

【问题讨论】:

标签: python postgresql enums sqlalchemy


【解决方案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))
    ...

【讨论】:

    【解决方案2】:

    我在 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")
    

    【讨论】:

      【解决方案3】:

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

      还有一个create_type kwarg 代表postgresql.ENUM。用于设置 alembic 迁移脚本中枚举类型列的架构。

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

      sa.Column('ActionType', postgresql.ENUM('Primary', 'Secondary', name='actiontype', create_type=False), nullable=True),
      
      

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

      我在需求文件中使用了SQLAlchemy==1.1.1 和alembic==0.8.8。

      我已经给出了类似的答案here。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-10-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-07-20
        • 2016-09-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多