SQLAlchemy使用Join检查约束

时间:2018-02-11 23:01:35

标签: python python-3.x postgresql sqlalchemy

我在SQLAlchemy中创建了多对多的关系,使用类似的东西:

b_c = Table('b_c', 
            Column('b_id', UUIDType(binary=False), ForeignKey('b.id'), primary_key=True),
            Column('c_id', UUIDType(binary=False), ForeignKey('c.id'), primary_key=True)
           )

cb只有id列(UUIDType(binary=false))的表格以及与此类似的模型:

class A(object):
    __tablename__ = 'a'
    id = Column('id', UUIDType(binary=False), default=uuid.uuid4, primary_key=True)

class B(object):
    __tablename__ = 'b'
    id = Column('id', UUIDType(binary=False), default=uuid.uuid4, primary_key=True)
    a_id = Column(UUIDType(binary=False), ForeignKey('a.id'), nullable=False)
    a = relationship('A')

class C(object):
    __tablename__ = 'c'
    id = Column('id', UUIDType(binary=False), default=uuid.uuid4, primary_key=True)
    a_id = Column(UUIDType(binary=False), ForeignKey('a.id'), nullable=False)
    a = relationship('A')

这种关系完全正常,我可以根据我的使用场景将B和C对象过滤到父A。但是,为了确保数据的完整性超出使用这些模型的逻辑,是否有任何最佳实践要求对于任何关系b_cb.a必须等于c.a

道歉,如果这个问题得到了回答,但是我发现的任何例子都是对表格本身的值的简单CHECK约束,没有任何要求连接表格的值。

1 个答案:

答案 0 :(得分:3)

来自文档:

  

Currently, CHECK expressions cannot contain subqueries nor refer to variables other than columns of the current row. The system column tableoid may be referenced, but not any other system column.

您所描述的内容不能通过检查约束来完成,但可以在插入或更新之前通过sql触发器实现:

这是一个postgresql函数&触发定义以检查引用表的a_id外键是否相等。

CREATE FUNCTION ckref_b_c() RETURNS trigger AS $ckref_b_c$
  DECLARE
  bid uuid;
  cid uuid;
  BEGIN
    select a_id INTO bid FROM b WHERE id = NEW.b_id;
    select a_id INTO cid FROM c WHERE id = NEW.c_id;
    IF bid != cid THEN 
        RAISE EXCEPTION 'associated records do not refer to same parent in `a`';
    END IF;
    RETURN NEW;
  END;
 $ckref_b_c$ LANGUAGE plpgsql;

CREATE TRIGGER ckref_b_c BEFORE INSERT OR UPDATE ON b_c
  FOR EACH ROW EXECUTE PROCEDURE ckref_b_c(); 

创建表后,您可以通过sqlalchemy引擎执行这些查询。 Sqlalchemy还有一个事件系统,您可以使用它来自动发出这些查询。