13

既に SQLAlchemy テーブル定義を使用しているプロジェクトに Alembic を組み込み始めています。現在、DB スキーマはアプリケーションの外部で管理されており、スキーマ全体をテーブル定義ファイルに取り込みたいと考えています。

PostgreSQL では、電子メール アドレスを格納するためにカスタム ドメインを使用しています。PostgreSQL DDL は次のとおりです。

CREATE DOMAIN email_address TEXT CHECK (value ~ '.+@.+')

SQLAlchemy で、このドメインの作成と列データ型としての使用をどのように表現すればよいですか?

4

2 に答える 2

1

これは実用的な解決策とはほど遠い可能性がありますが、これを行う最善の方法は subclass だと思いますsqlalchemy.schema._CreateDropBase

from sqlalchemy.schema import _CreateDropBase

class CreateDomain(_CreateDropBase):
    '''Represent a CREATE DOMAIN statement.'''

    __visit_name__ = 'create_domain'

    def __init__(self, element, bind=None, **kw):
        super(CreateDomain, self).__init__(element, bind=bind, **kw)

class DropDomain(_CreateDropBase):
    '''Represent a DROP BASE statement.'''

    __visit_name__ = 'drop_domain'

    def __init__(self, element, bind=None, **kw):
        super(DropDomain, self).__init__(element, bind=bind, **kw)

@compiles(CreateDomain, 'postgresql')
def visit_create_domain(element, compiler, **kw):
    text = '\nCREATE DOMAIN %s AS %s' % (
        compiler.prepare.format_column(element.name),
        compiler.preparer.format_column(element.type_)) # doesn't account for arrays and such I don't think

    default = compiler.get_column_default_string(column)
    if default is not None:
        text += " DEFAULT %s" % default

    return text

明らかに、これは不完全ですが、これがどうしても必要な場合は、良い出発点になるはずです。:)

于 2015-11-02T15:24:10.977 に答える
1

SQLAlchemy のようなものを使用する理由の 1 つは、DB の独立性です (ORM は別として)。

ただし、多くの場合非常に DB 固有であるこのような低レベルの構成を使用すると、「DB の独立性」が非引数になるためop.execute、alembic 移行で単純に記述することを選択します。

これは、ソース コードがはるかに単純になり、エラーが発生しにくくなるため、多くの場合、非常に受け入れられるトレードオフです。

1 つの DB バックエンドでのみ利用可能な DB の機能に依存している場合 (別の例は、ltreeまたはhstorePostgreSQL である可能性があります)、そのターゲット バックエンドでのみ機能する移行を使用しても問題はありません。終わり。

したがって、次のことができます。

def upgrade():
    op.execute("CREATE DOMAIN ...")

def downgrade():
    op.execute("DROP DOMAIN ...")

一方、異なるバックエンドをサポートする予定がある場合、これは機能しません。

于 2020-07-01T10:22:20.813 に答える