SQLAlchemy Association Proxy - 防止重复条目

时间:2018-02-24 02:04:33

标签: python sqlalchemy

我正在使用Association Proxy设置间接的多对多关系,其中Submission可以包含多个Role,而Role可以是与多个Submission相关联。请注意,我还使用flask-sqlalchemy

class Role(db.Model):
    __tablename__ = 'role'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.Text)

    def __init__(self, name):
        self.name = name

class Submission(db.Model):
    __tablename__ = 'submission'
    id = db.Column(db.Integer, primary_key=True)

    submission_to_role = relationship("SubmissionToRole", cascade="all, delete-orphan")
    roles = association_proxy('submission_to_role', 'role')


class SubmissionToRole(db.Model):
    __tablename__ = 'submission_to_role'

    submission_id = db.Column(db.Integer, db.ForeignKey('submission.id', ondelete='CASCADE'), primary_key=True)
    role_id = db.Column(db.Integer, db.ForeignKey('role.id', ondelete='CASCADE'), primary_key=True)
    submission = relationship(Submission)
    role = relationship(Role)

    def __init__(self, role):
        self.role = role

我需要这样的行为:

submission = Submission()
role_a = Role('Backend Developer')
role_b = Role('Frontend Developer')
db.session.add(submission)
db.session.add(role_a)
db.session.add(role_b)
db.session.commit()

submission.roles.append(role_a) # submission.roles length should become 1
submission.roles.append(role_b) # submission.roles length should become 2
submission.roles.append(role_a) # submission.roles length should remain 2, since I already associated role_a previously.

但是,当我关联已经关联的Role时,SQLAlchemy会创建一个重复的关联对象。

我如何实现我想要的行为?我写了一个Submission的函数来解决它

def associate_role(self, role):
        assoc_model = SubmissionToRole.query.filter(
            SubmissionToRole.submission_id == self.id
        ).filter(
            SubmissionToRole.role_id == role.id
        ).first()
        if not assoc_model:
            self.roles.append(role)

但想要更清洁,更容易重复使用的东西。我可以使用SQLAlchemy原生的东西吗?

1 个答案:

答案 0 :(得分:0)

您可以在 SubmissionToRole 上创建一个 UniqueConstraint,这让您可以指定多对多表将分别具有 RoleSubmission 的重复值,RoleSubmission 值的 pairings 不应重复。这称为复合唯一约束。

from sqlalchemy import UniqueConstraint


class SubmissionToRole(db.Model):
    __tablename__ = 'submission_to_role'

    submission_id = db.Column(db.Integer, db.ForeignKey('submission.id', ondelete='CASCADE'), primary_key=True)
    role_id = db.Column(db.Integer, db.ForeignKey('role.id', ondelete='CASCADE'), primary_key=True)
    submission = relationship(Submission)
    role = relationship(Role)

    def __init__(self, role):
        self.role = role

    # explicit/composite unique constraint.  'name' is optional.
    __table_args__ = (UniqueConstraint('submission', 'role', name='submission_role_uc'),
                     )