Opened 14 years ago
Last modified 14 years ago
#14223 closed
Inconsistent exception raising on DB integrity errors — at Initial Version
Reported by: | Ramiro Morales | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | dev |
Severity: | Keywords: | integrityerror backends orm | |
Cc: | Triage Stage: | Accepted | |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
It seems we aren't capturing the <db api driver module>.IntegrityError
exceptions raised when connection.commit() is executed
in the same way we do in execute()
.
Found this while creating tests to verify FK constraint in sqlite (#14304). My assertRaises(django.db.[utils.]IntegrityError, ...)
weren't being triggered and printing the exception type shows <class 'pysqlite2.dbapi2.IntegrityError'>
. Same thing happens now with postgres (see below).
The DatabaseError
and IntegrityError
unification was introduced in r12352, if this is confirmed as an issue it wouldn't be a regression in 1.2, but a 1.2 feature introduced in an incomplete fashion.
The two files pasted at the end form a small test case. When run under postgres you see:
====================================================================== ERROR: Try to create a model instance that violates a FK constraint. Should fail ---------------------------------------------------------------------- Traceback (most recent call last): File "/home/r/django/sqlite_fk2/tests/regressiontests/fk_constraints/tests.py", line 22, in test_integrity_checks_on_creation a.save() File "/home/r/django/sqlite_fk2/django/db/models/base.py", line 434, in save self.save_base(using=using, force_insert=force_insert, force_update=force_update) File "/home/r/django/sqlite_fk2/django/db/models/base.py", line 534, in save_base transaction.commit_unless_managed(using=using) File "/home/r/django/sqlite_fk2/django/db/transaction.py", line 175, in commit_unless_managed connection._commit() File "/home/r/django/sqlite_fk2/django/db/backends/__init__.py", line 32, in _commit return self.connection.commit() IntegrityError: insert or update on table "fk_constraints_article" violates foreign key constraint "fk_constraints_article_reporter_id_fkey" DETAIL: Key (reporter_id)=(30) is not present in table "fk_constraints_reporter". <class 'psycopg2.IntegrityError'>
# models.py from django.db import models class Reporter(models.Model): first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=30) email = models.EmailField() def __unicode__(self): return u"%s %s" % (self.first_name, self.last_name) class Article(models.Model): headline = models.CharField(max_length=100) pub_date = models.DateField() reporter = models.ForeignKey(Reporter) def __unicode__(self): return self.headline class Meta: ordering = ('headline',)
# tests.py from datetime import datetime from django.db import utils from django.test import TransactionTestCase from models import Reporter, Article import sys class FkConstraintsTest(TransactionTestCase): def setUp(self): # Create a Reporter. self.r = Reporter.objects.create(first_name='John', last_name='Smith', email='john@example.com') #self.r2 = Reporterobjects.create(first_name='Paul', last_name='Jones', email='paul@example.com') def test_integrity_checks_on_creation(self): """Try to create a model instance that violates a FK constraint. Should fail""" a = Article(headline="This is a test", pub_date=datetime(2005, 7, 27), reporter_id=30) #self.assertRaises(utils.IntegrityError, a.save) try: a.save() except Exception, e: print >>sys.stderr, type(e) raise def test_integrity_checks_on_update(self): """Try to update a model instance introducing a FK constraint violation. Should fail""" # Create an Article. Article.objects.create(headline="Test article", pub_date=datetime(2010, 9, 4), reporter=self.r) # Retrive it from the DB a = Article.objects.get(headline="Test article") a.reporter_id = 30 #self.assertRaises(utils.IntegrityError, a.save) try: a.save() except Exception, e: print >>sys.stderr, type(e) raise