【问题标题】:Is it possible to set a Boolean column as a unique constraint in Flask-SQLalchemy?是否可以将布尔列设置为 Flask-SQLalchemy 中的唯一约束?
【发布时间】:2019-03-29 13:31:14
【问题描述】:

是否可以以在任何给定时间只能将一条记录设置为 true 的方式设置表?

我有一个“用户”表和一个“凭据”表。一个用户可以拥有一个或多个与之关联的登录凭据。一次只能有一个“活动”凭据,由凭据表中的“活动”列(布尔值)指示。

是否可以设置某种约束来防止两条记录同时“活动”?

【问题讨论】:

标签: python flask sqlalchemy flask-sqlalchemy


【解决方案1】:

您可以使用唯一约束来防止 2 列同时处于活动状态,但您必须使用 True 和 None 作为可能的值,而不是 True 和 False。这是因为唯一约束在列中只允许一个 True,但也只允许一个 False。 None(或 SQL NULL)值不参与唯一约束,因此您可以拥有与剩余行一样多的这些。为了确保数据库的完整性,最好使用只有一个可能值的枚举数据类型来实现。

import enum

class Active(enum.Enum):
    true = True

class Credentials(db.Model):
    active = db.Column(db.Enum(Active), unique=True)

您现在可以使用 Active.true 作为值来指示活动凭据,而 None 用于在数据库级别强制执行完整性的所有其他凭据。如果您打算让每个用户拥有一个活动凭据,而不是总共拥有一个活动凭据,则可以使用单独的 UniqueConstraint 语句来实现。

class Credential(db.Model):
    __tablename__ = "credentials"
    __table_args__ = (db.UniqueConstraint('user_id', 'active'),)

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
    user = db.relationship("User", back_populates="credentials")
    active = db.Column(db.Enum(Active))

class User(db.Model):
    __tablename__ = "users"

    id = db.Column(db.Integer, primary_key=True)
    credentials = db.relationship("Credential", back_populates="user")

虽然这确实可以防止多个凭据被标记为活动,但它不会阻止用户没有活动凭据,您需要依赖您的应用程序逻辑来实现这一点。

【讨论】:

    【解决方案2】:

    所以如果我没看错,你有两个模型类 UserCredential 这是一对多的关系:

    class User(db.Model):
        ...
        credentials = db.relationship('Credential')
    
    class Credential(db.Model):
        ...
        user_id = db.Column(db.Integer, db.ForeignKey('user.id', nullable=False)
    

    是否可以添加一个额外的外键来表示一对一的关系:

    class User(db.Model):
        ...
        active_credential_id = db.Column(db.Integer, db.ForeignKey('credential.id'))
    
    class Credential(db.Model):
        ...
        active_user = db.relationship('User')
    

    您可以使用以下内容更新此内容:

    inactive_credential = # some credential from the user's list of credentials
    user = User.query.filter(User.id == inactive_credential.user_id)
    user.active_credential_id = inactive_credential.id
    db.session.add(user)
    db.session.commit()
    # inactive_credential ==>> active_credential
    

    这里使用外键来维护数据库的完整性。

    您将需要一些额外的约束,即只能从用户由 user_id 定义的凭据列表中选择 active_credential_id。我最后只是想到了这一点,如果我有解决方案,稍后会更新答案。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-11-18
      • 1970-01-01
      • 2021-04-10
      • 2015-01-06
      • 2016-02-26
      • 2016-08-22
      • 2011-01-30
      相关资源
      最近更新 更多