I have this code:
try:
principal = cls.objects.create(
user_id=user.id,
email=user.email,
path='something'
)
except IntegrityError:
principal = cls.objects.get(
user_id=user.id,
email=user.email
)
It tries to create a user with the given id and email, and if there already exists one - tries to get the existing record.
I know this is a bad construction and it will be refactored anyway. But my question is this:
How do i determine what kind of IntegrityError
has happened: the one related to unique
constraint violation (there is unique key on (user_id, email)) or the one related to not null
constraint (path
cannot be null)?
Update as of 9-6-2017:
A pretty elegant way to do this is to
try
/except IntegrityError as exc
, and then use some useful attributes onexc.__cause__
andexc.__cause__.diag
(a diagnostic class that gives you some other super relevant information on the error at hand - you can explore it yourself withdir(exc.__cause__.diag)
).The first one you can use was described above. To make your code more future proof you can reference the psycopg2 codes directly, and you can even check the constraint that was violated using the diagnostic class I mentioned above:
edit for clarification: I have to use the
__cause__
accessor because I'm using Django, so to get to the psycopg2 IntegrityError class I have to callexc.__cause__
psycopg2 provides the
SQLSTATE
with the exception as thepgcode
member, which gives you quite fine-grained error information to match on.See Appendix A: Error Codes in the PostgreSQL manual for code meanings. Note that you can match coarsely on the first two chars for broad categories. In this case I can see that SQLSTATE 42601 is
syntax_error
in theSyntax Error or Access Rule Violation
category.The codes you want are:
so you could write:
That said, this is a bad way to do an
upsert
ormerge
. @pr0gg3d is presumably right in suggesting the right way to do it with Django; I don't do Django so I can't comment on that bit. For general info on upsert/merge see depesz's article on the topic.It could be better to use:
as in https://docs.djangoproject.com/en/dev/ref/models/querysets/#get-or-create
The
IntegrityError
should be raised only in the case there's aNOT NULL
constraint violation. Furthermore you can usecreated
flag to know if the object already existed.