これが私の投稿モデルです:
class Post(Base):
__tablename__ = 'posts'
title = db.Column(db.String(120), nullable=False)
description = db.Column(db.String(2048), nullable=False)
列挙型status
を追加したいと思います。だから、私は新しい列挙型を作成しました:
import enum
class PostStatus(enum.Enum):
DRAFT='draft'
APPROVE='approve'
PUBLISHED='published'
そして、モデルに新しいフィールドを追加しました。
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))
DBをアップグレードしようとすると、次のようになります。
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"]
poststatus
がDBレベルで自動的に作成されなかったのはなぜですか?同様の移行では、そうでした。server_default
オプションを正しく指定するにはどうすればよいですか?既存の行を変更しているため、ORMレベルのデフォルトとDBレベルのデフォルトの両方が必要です。ORMのデフォルトは適用されません。draft
などではないのはなぜですか?名前ではなく、ENUM値があるべきだと思いました。前もって感謝します。
DBの実際の値が「ドラフト」、「承認」、「公開」であるのに、ドラフトなどではないのはなぜですか?名前ではなく、ENUM値があるべきだと思いました。
PeterBašistaがすでに述べたように、SQLAlchemyはデータベースで列挙名(DRAFT、APPROVE、PUBLISHED)を使用します。列挙値( "draft"、 "approve"、...)はPython)の任意の型であり、一意であることが保証されていないため(@unique
が使用されていない限り)、これが行われたと思います。 )。
ただし、SQLAlchemy 1.2.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
)
タイプpoststatusがDBレベルで自動的に作成されなかったのはなぜですか?同様の移行では、そうでした。
基本的に、アレムビックの制限に直面していると思います。PostgreSQLで列挙型を正しく処理できない場合があります。あなたの場合の主な問題は Autogenerateがpostgresql列挙型#278を正しく処理しない だと思います。
alembic.op.create_table
を使用すると、型が正しく作成されることに気付いたので、回避策は基本的に次のとおりです。
enum_type = SQLEnum(PostStatus, values_callable=lambda enum: [e.value for e in enum])
op.create_table(
'_dummy',
sa.Column('id', Integer, primary_key=True),
sa.Column('status', enum_type)
)
op.drop_table('_dummy')
c_status = Column('status', enum_type, nullable=False)
add_column('posts', c_status)
私はあなたの質問の3番目の部分にしか答えることができません。
SQLAlchemyのEnum
型の documentation は、次のように述べています。
上記では、各要素の文字列名。 「1」、「2」、「3」はデータベースに保持されます。 Python列挙型(ここでは整数で示されています)の値は使用されません;したがって、各列挙型の値は使用できます永続性があるかどうかに関係なく、あらゆる種類のPythonオブジェクトである必要があります。
したがって、SQLAlchemyの設計により、値ではなくEnum
namesがデータベースに永続化されます。