python - sqlalchemy 是否可以添加字段级别规则,即两个特定列不能同时为 None?

标签 python sqlalchemy flask-sqlalchemy

我有一个如下所示的模型:

class Foo(db.Model):

    id = db.Column(db.Integer, primary_key=True)

    # omitted lengthy codes...

    spam = db.relationship('Spam')
    spam_id = db.Column(db.Integer, db.ForeignKey('spams.id'))

    bar = db.relationship('Bar')
    bar_id = db.Column(db.Integer, db.ForeignKey('bars.id'))

    created = db.Column(db.DateTime, server_default=db.func.now())

Flask-SQLAlchemy 是否有任何选项可用于添加插入/更新期间 spam_idbar_id 不能同时为 None 的行为?但如果这些列中至少一列具有值,则将接受。

最佳答案

您可以使用 table constraint here

from sqlalchemy import CheckConstraint


class Foo(db.Model):

    id = db.Column(db.Integer, primary_key=True)

    # omitted lengthy codes...

    spam = db.relationship('Spam')
    spam_id = db.Column(db.Integer, db.ForeignKey('spams.id'))

    bar = db.relationship('Bar')
    bar_id = db.Column(db.Integer, db.ForeignKey('bars.id'))

    created = db.Column(db.DateTime, server_default=db.func.now())

    __table_args__ = (
        CheckConstraint('NOT(spam_id IS NULL AND bar_id IS NULL)', name='both_null'),
    )

尝试使用 spam_id 和 None 添加新的 Foo 实例?好的,你可以

foo=Foo(spam_id=None, bar_id=1)
sqlalchemy_session.add(foo)
sqlalchemy_session.commit()

尝试在 None 处添加带有 spam_id 和 bar_id 的 Foo 吗?不,先生!

foo=Foo(spam_id=None, bar_id=None)
sqlalchemy_session.add(foo)
sqlalchemy_session.commit()  # Raises Exception

引发的异常来自您的 DBMS,例如 PostgresQL 和 psycopg2 驱动程序,它是 psycopg2.IntegrityError

关于python - sqlalchemy 是否可以添加字段级别规则,即两个特定列不能同时为 None?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52260371/

相关文章:

python - 使用 Python 正则表达式匹配不带点的单词

python - 在我的代码中添加边框和图像

python - 在 scipy.spatial.Delaunay python 中找到一个点是其一部分的所有单纯形

python - flask/sqlalchemy _init_() 添加数据库条目时出现类型错误?

sqlalchemy - 如何获取所有不处于多对多关系的行

python - 使用 Bottle 上传和处理 CSV 文件;可能的编码问题

python - 覆盖 sqlalchemy 反射表中的默认值

python - 搜索功能(在Flask、SQLAlchemy中查询)

python - SQLAlchemy Python 3 Ubuntu 16.04

python - 为什么我收到 SQLAlchemy 错误 "__table_args__ value must be a tuple, dict, or None"