The integrity error will tell you which column has violated the constraint. For example:
IntegrityError: (IntegrityError) insert or update on table "my_table"
violates foreign key constraint "my_table_some_column_fkey"
In your case you are declaring your constraint like this:
UniqueConstraint('datapath_port_id', 'datapath_id',
'controller_id', name='unique_registration')
What you are doing here is not declaring multiple uniqueness constrains. That would look something like this:
Column('datapath_port_id', unique=True)
Column('datapath_id', unique=True)
Column('controller_id', unique=True)
Instead you have created a multicolumn or composite uniqueness constraint which means that the combination of all three columns must be unique.
So if you had a database row A, B, C
with your multicolumn uniqueness constraint you could still insert A, A, A
even though there is already the value A
in the first row. Similarly, B, B, B
and C, C, C
would also be valid inserts. What would fail though is trying to insert A, B, C
again. That fails because all the columns match an existing row, which is why the uniqueness error you're seeing lists all the columns.
Here is an example with code:
from sqlalchemy import create_engine
from sqlalchemy import Column, Integer
from sqlalchemy import UniqueConstraint
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
engine = create_engine('sqlite:///:memory:', echo=True)
Base = declarative_base()
class Test(Base):
__tablename__ = 'test'
__table_args__ = (
UniqueConstraint('a', 'b', name='ab_constraint'),
UniqueConstraint('b', 'c', name='bc_constraint'))
id = Column(Integer, primary_key=True)
a = Column(Integer)
b = Column(Integer)
c = Column(Integer)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
session = Session()
session.add(Test(a=1, b=1, c=1))
session.add(Test(a=2, b=2, c=2))
From there we can try to violate the different uniqueness constraints to see what happens. If try to run this command:
session.add(Test(a=1, b=1, c=2))
session.commit()
We get:
sqlalchemy.exc.IntegrityError: (IntegrityError) UNIQUE constraint failed: test.a, test.b u'INSERT INTO test (a, b, c) VALUES (?, ?, ?)' (1, 1, 2)
And then if we try to violate the second constraint:
session.add(Test(a=1, b=2, c=2))
session.commit()
We instead get:
sqlalchemy.exc.IntegrityError: (IntegrityError) UNIQUE constraint failed: test.b, test.c u'INSERT INTO test (a, b, c) VALUES (?, ?, ?)' (1, 2, 2)
With the first case specifying that test.a
and test.b
violated the constraint and the second one specifying test.b
and test.c
.
The names I chose for those constraints (ab_constraint
and bc_constraint
) are however are not included in the response. They are however present in at the database level. We can see this by echoing the database creation commands:
CREATE TABLE test (
id INTEGER NOT NULL,
a INTEGER,
b INTEGER,
c INTEGER,
PRIMARY KEY (id),
CONSTRAINT ab_constraint UNIQUE (a, b),
CONSTRAINT bc_constraint UNIQUE (b, c)
)
However, even at the database level (I'm using SQLite) the constraint name is not used in the error message:
sqlite> INSERT INTO test (a, b, c) VALUES (1, 1, 1);
sqlite> INSERT INTO test (a, b, c) VALUES (2, 2, 2);
sqlite> INSERT INTO test (a, b, c) VALUES (1, 1, 2);
Error: UNIQUE constraint failed: test.a, test.b