如何在SQLAlchemy和Alembic中使用Enum?

2024-10-01 05:06:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我的帖子:

class Post(Base):
    __tablename__ = 'posts'

    title = db.Column(db.String(120), nullable=False)
    description = db.Column(db.String(2048), nullable=False)

我想添加枚举status。所以,我创建了一个新的枚举:

^{pr2}$

并在模型中添加了一个新字段:

class Post(Base):
    ...
    status = db.Column(db.Enum(PostStatus), nullable=False, default=PostStatus.DRAFT.value, server_default=PostStatus.DRAFT.value)

完成FLASK_APP=server.py flask db migrate后,生成了这样的迁移:

def upgrade():
    op.add_column('posts', sa.Column('status', sa.Enum('DRAFT', 'APPROVE', 'PUBLISHED', name='poststatus'), server_default='draft', nullable=False))

在尝试升级数据库后,我得到:

sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) type "poststatus" does not exist
LINE 1: ALTER TABLE posts ADD COLUMN status poststatus DEFAULT 'draf...
                                            ^
 [SQL: "ALTER TABLE posts ADD COLUMN status poststatus DEFAULT 'draft' NOT NULL"]
  1. 为什么类型poststatus没有在数据库级别自动创建?在类似的迁移过程中也是如此。在
  2. 如何正确指定server_default选项?我需要ORM级别的默认值和DB级别的默认值,因为我正在更改现有行,所以ORM默认值不适用。在
  3. 为什么DB中的实际值是'DRAFT'、'APPROVE'、'PUBLISHED',而不是{}等等?我想应该有枚举值,而不是名称。在

提前谢谢你。在


Tags: falsedefaultdbbaseserverstatuscolumn级别
3条回答

我只能回答你问题的第三部分。在

SQLAlchemy中Enum类型的documentation声明:

Above, the string names of each element, e.g. “one”, “two”, “three”, are persisted to the database; the values of the Python Enum, here indicated as integers, are not used; the value of each enum can therefore be any kind of Python object whether or not it is persistable.

因此,正是通过SQLAlchemy设计,Enum名称,而不是将值持久化到数据库中。在

来自官方文件:https://docs.python.org/3/library/enum.html#creating-an-enum

import enum

class PostStatus(enum.Enum):
    DRAFT = 0
    APPROVE = 1
    PUBLISHED = 2

据此:

^{pr2}$

1)PostStatus不是DB模型,它只是一个包含状态ID的类

2)没事

3)你不必在数据库中存储状态字符串,你最好改用id

Why real values in DB are 'DRAFT', 'APPROVE', 'PUBLISHED', but not draft, etc? I supposed there should be ENUM values, not names.

正如peterbašista已经提到的那样,SQLAlchemy在数据库中使用枚举名称(DRAFT、APPROVE、PUBLISHED)。我假设这样做是因为枚举值(“draft”、“approve”、…)可以是Python中的任意类型,并且不能保证它们是唯一的(除非使用@unique)。在

然而,由于SQLAlchemy 1.2.3,因此Enum类接受一个参数values_callable,该参数可用于在数据库中存储枚举值

    status = db.Column(
        db.Enum(PostStatus, values_callable=lambda obj: [e.value for e in obj]),
        nullable=False,
        default=PostStatus.DRAFT.value,
        server_default=PostStatus.DRAFT.value
    )

Why type poststatus was not created on DB-level automatically? In the similar migration it was.

我认为基本上你遇到了alembic的一个限制:在某些情况下,它不能正确地处理PostgreSQL上的枚举。我怀疑你的案子的主要问题是Autogenerate doesn't correctly handle postgresql enums #278。在

我注意到,如果我使用alembic.op.create_table创建的类型是正确的,所以我的解决方法基本上是:

^{pr2}$

相关问题 更多 >