如何在SQLAlchemy中表示自定义PostgreSQL域?

时间:2013-09-06 16:57:07

标签: python orm sqlalchemy alembic sql-domain

我开始将Alembic合并到已经使用SQLAlchemy表定义的项目中。目前我的数据库架构是在我的应用程序外部管理的,我想将整个架构带入我的表定义文件。

在PostgreSQL中,我使用自定义域来存储电子邮件地址。 PostgreSQL DDL是:

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

如何在SQLAlchemy中表示此域的创建及其作为列数据类型的用法?

2 个答案:

答案 0 :(得分:0)

这可能远不是一个有效的解决方案,但我认为最好的方法是子类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

显然,这是不完整的,但如果你想要这么做的话,它应该给你一个很好的起点。 :)

答案 1 :(得分:0)

使用诸如SQLAlchemy之类的原因之一是数据库独立性(除了ORM之外)。

但是,使用这样的低级结构(通常是非常特定于DB的)使“ DB独立性”成为一个非参数,因此,我会选择在您的Alembic迁移中编写一个简单的op.execute

这通常是一个非常可接受的折衷方案,因为它使源代码更简单并且更不容易出错。

如果您依赖于仅在一个数据库后端中可用的数据库功能(另一个示例可能是PostgreSQL的ltreehstore),那么我看不到任何问题使用仅适用于该目标后端的迁移。

所以您可以这样做:

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

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

另一方面,如果您计划支持其他后端,则将无法使用。