如何使用CheckConstraint计算多对多关系?

时间:2018-04-20 06:52:15

标签: python sqlalchemy

我有一个基本的Person表。每个人最多可以有5个朋友。我希望强制执行检查数据库级约束。

我已尝试使用此处所述的func.counthttp://docs.sqlalchemy.org/en/latest/orm/tutorial.html#counting),但没有成功,收到此错误:

sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) misuse of aggregate function count()

这是我的代码:

friend_table = Table(
    'friend', Base.metadata,
    Column('left_id', Integer, ForeignKey('person.id')),
    Column('right_id', Integer, ForeignKey('person.id'))
)


class Person(Base):
    __tablename__ = 'person'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    friends = relationship('Person',
                           secondary=friend_table,
                           primaryjoin=friend_table.c.left_id == id,
                           secondaryjoin=friend_table.c.right_id == id)

    __table_args__ = (
        CheckConstraint(func.count(friends) < 5, name='max_friends_constraint'),
    )

1 个答案:

答案 0 :(得分:0)

回答这个旧问题,因为我找不到其他令人满意的答案。根据我的调查,CheckConstraint并不是使用JOIN查询是不可能的,但是效率很低。

但是,可以使用event代替,检查append出现时的号码,以强制最大数量的朋友。下面的代码示例应符合您的预期情况:

from sqlalchemy import event
from sqlalchemy.exc import IntegrityError

@event.listens_for(Person.friends, "append")
def receive_append(target, value, initiator):
    if len(target.friends) >= 5:
        # Raising this exc just as an example, just adapt to your needs
        raise IntegrityError("person.friends.append", None, None)

    # This returns the value, hence the friend will be appended normally
    return value

如果仅打算使用sqlalchemy,这应该是一个很好的解决方案。如果您打算使用原始查询以任何其他形式与Db进行交互,则可能需要为关联表trigger附加一个friend来执行您的规则。