这可能是完全愚蠢的问题但我在我的模型中有这样一个要求:至少category
或parent_category
是not null
我的模型看起来像
class BudgetCategories(db.Model):
__tablename__ = 'budget_categories'
uuid = Column('uuid', GUID(), default=uuid.uuid4, primary_key=True,
unique=True)
budget_id = Column(GUID(), ForeignKey('budgets.uuid'), nullable=False)
budget = relationship('Budget', backref='budgetCategories')
category = Column('category', sa.types.String, nullable=True)
parent_category = Column('parent_category', sa.types.String, nullable=True)
amount = Column('amount', Numeric(10, 2), nullable=False)
recurring = Column('recurring', sa.types.Boolean,
nullable=False)
created_on = Column('created_on', sa.types.DateTime(timezone=True),
nullable=False)
我该如何指定。我甚至不知道该尝试什么
赞赏任何指针
我使用PostgreSQL
作为后端数据库
答案 0 :(得分:11)
我对PostgreSQL
语法不是100%肯定,但是添加到BudgetCategories
模型之后应该使用CheckConstraint
来解决问题:
class BudgetCategories(Base):
__tablename__ = 'budget_categories'
# ...
# @note: new
__table_args__ = (
CheckConstraint('NOT(category IS NULL AND parent_category IS NULL)'),
)
答案 1 :(得分:3)
我在SQLalchemy模型中需要 XOR 行为。我提出了以下定义(使用的后端:PostgreSQL):
from sqlalchemy.schema import (
CheckConstraint
)
class ScheduledNotebook(Base):
__table_args__ = (
(CheckConstraint('(uuid::text IS NULL) <> (notebook_path IS NULL)', name='uuid_xor_notebook_path')),
)
id = Column(Integer, primary_key=True)
notebook_path = Column(String, nullable=True, unique=True)
uuid = Column(UUID(as_uuid=True), primary_key=True, unique=True, nullable=True)
以及随后的Alembic迁移(注意:自动生成不会检测到它-您必须手动添加):
def upgrade():
op.create_check_constraint(
'uuid_xor_notebook_path',
table_name='scheduled_notebooks',
schema='metadata',
condition='(uuid::text IS NULL) <> (notebook_path IS NULL)'
)
def downgrade():
op.drop_constraint('uuid_xor_notebook_path')
它就像一种魅力:
-仅笔记本路径-确定
datalake=# INSERT INTO scheduled_notebooks (schedule,enabled,owner, notebook_path) VALUES ('{"kind":"hourly"}',true,'akos', '/a/b/c/d/e.ipynb');
INSERT 0 1
-仅用于uuid-确定
datalake=# INSERT INTO scheduled_notebooks (schedule,enabled,owner, uuid) VALUES ('{"kind":"hourly"}',true,'akos', '7792bd5f-5819-45bf-8902-8cf43102434d');
INSERT 0 1
-uuid和notebook_path均-失败,根据需要
datalake=# INSERT INTO scheduled_notebooks (schedule,enabled,owner, uuid, notebook_path) VALUES ('{"kind":"hourly"}',true,'akos', '7792bd5f-5819-45bf-8902-8cf43102434f', '/a/b/c/d');
ERROR: new row for relation "scheduled_notebooks" violates check constraint "uuid_xor_notebook_path"
DETAIL: Failing row contains (567, /a/b/c/d, {"kind": "hourly"}, t, akos, null, null, null, 7792bd5f-5819-45bf-8902-8cf43102434f).
-既不是uuid也不是notebook_path-根据需要失败
datalake=# INSERT INTO scheduled_notebooks (schedule,enabled,owner) VALUES ('{"kind":"hourly"}',true,'akos');
ERROR: new row for relation "scheduled_notebooks" violates check constraint "uuid_xor_notebook_path"
DETAIL: Failing row contains (568, null, {"kind": "hourly"}, t, akos, null, null, null, null).
答案 2 :(得分:-1)
我希望还不算太晚,但是这应该可以解决问题,并且检查它是否适用于PostGreSQL数据库:
class BudgetCategories(Base):
__tablename__ = 'budget_categories'
__table_args__ = (
CheckConstraint('coalesce(category , parent_category ) is not null'),
)
# ...