Reputation: 1228
I have created a many to many relationship in SQLAlchemy using something like this:
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)
)
Where c
and b
are tables with only an id
column (UUIDType(binary=false)
) and the models similar to this:
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')
This relationship works perfectly fine, and I'm able to filter the B and C objects to a parent A for my usage scenario. However, to ensure integrity of the data beyond the logic that uses these models, is there any best practice for requiring that for any relation b_c
, b.a
must equal c.a
?
Apologies if this is answered elsehwere, but any examples I have found are simple CHECK constraints against values in the table itself, and nothing requiring values of joined tables.
Upvotes: 5
Views: 2031
Reputation: 28313
From the documentation:
What you are describing cannot be done via check constraints, but may be achieved via sql triggers before insert or update:
Here's a postgresql function & trigger definition to check for equality of the referred table's a_id
foreign key.
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();
You can execute these queries through the sqlalchemy engine after the tables are created. Sqlalchemy also has an event system which you could use to emit these queries automatically.
Upvotes: 8