在一对多关系中限制许多人的数量

时间:2014-10-26 01:18:51

标签: python sqlalchemy flask-sqlalchemy

我试图使用Flask-SQLAlchemy限制一对多中'many'的数量。我希望每个'盲'行只允许3个或更少的'鼠标'(小鼠)。

这是我的基本设置......

class Blind(db.Model):
    __tablename__   = 'blind'
    #this __table_args__ does not work
    #__table_args__  = ((db.CheckConstraint('length(blind_mice <= 3)')),)
    id              = db.Column(db.Integer, primary_key=True)

    # I want to limit the blind_mice
    #relationship to a count of 3 mice per 'Blind' id
    blind_mice      = db.relationship('Mouse')


class Mouse(db.Model):
    __tablename__   = 'mouse'
    id              = db.Column(db.Integer, primary_key=True)
    blind_id    = db.Column(db.Integer, db.ForeignKey('blind.id'))
    blind       = db.relationship("Blind")

我尝试使用sqlalchemy的CheckConstraint(参见上面注释掉的__table_args__),但这会导致错误:

sqlalchemy.exc.OperationalError: (OperationalError) no such column: blind_mice u'\nCREATE 
TABLE blind (\n\tid INTEGER NOT NULL, \n\tPRIMARY KEY (id), \n\tCHECK (length(blind_mice 
<= 3))\n)\n\n' ()

感谢任何帮助。

1 个答案:

答案 0 :(得分:0)

在解决这个问题几个小时后,我开始查看sqlalchemy事件文档。这是我能想到的最好的。

from sqlalchemy import event
from sqlalchemy.exc import IntegrityError

MAX_MICE_PER_BLIND = 3


class Blind(db.Model):
    __tablename__       = 'blind'
    id                  = db.Column(db.Integer, primary_key=True)
    blind_mice          = db.relationship('Mouse')


class Mouse(db.Model):
    __tablename__   = 'mouse'
    id              = db.Column(db.Integer, primary_key=True)
    blind_id        = db.Column(db.Integer, db.ForeignKey('blind.id'))
    blind           = db.relationship("Blind")


@event.listens_for(Mouse.blind_id, 'set', retval=True)
def mice_per_blind_check(target, value, oldvalue, initiator):
    if value is not None:
        mice_count = Mouse.query.filter_by(blind_id=value).count()
        if mice_count >= MAX_MICE_PER_BLIND:
            orig = Exception('Maximum number of Mice ({}) '\
                             'reached for Blind.id = {}'\
                             .format(MAX_MICE_PER_BLIND, value))
            msg = "Record Not Committed"
            raise IntegrityError(msg, ';)', orig)
    return value

此解决方案抛出IntegrityError,当与Flask-Restless一起使用时会导致HTTP 400错误请求,但不会中断Flask服务器操作。此外,该解决方案不允许存在具有blind_id = n的第4只鼠标。伟大的成功!