I have a unique_together constraint for email and store. I have used the following code to test the unique constraint. I'm expecting to pass the test with assertRaise but the result shows the opposite. What I'm missing here?
from django.db.backends.sqlite3.base import IntegrityError
class TestUserModel(TestCase):
def setUp(self):
self.store1 = Store.objects.create(name='store1')
self.store2 = Store.objects.create(name='store2')
def multiple_user_with_same_email_and_store(self):
data1 = dict(email="[email protected]", password="a", store=self.store1)
data2 = dict(email="[email protected]", password="abc", store=self.store1)
self.user1 = User.objects.create(**data1)
user2 = User(**data2)
self.assertRaises(IntegrityError, user2.save)
Traceback
Creating test database for alias 'default'...
E
======================================================================
ERROR: multiple_user_with_same_email_and_store (user.tests.test_models.TestUserModel)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/ram/nk/project/helper/helper/user/tests/test_models.py", line 25, in multiple_user_with_same_email_and_store
self.assertRaises(IntegrityError, user2.save)
File "/usr/lib/python2.7/unittest/case.py", line 473, in assertRaises
callableObj(*args, **kwargs)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/base.py", line 734, in save
force_update=force_update, update_fields=update_fields)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/base.py", line 762, in save_base
updated = self._save_table(raw, cls, force_insert, force_update, using, update_fields)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/base.py", line 846, in _save_table
result = self._do_insert(cls._base_manager, using, fields, update_pk, raw)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/base.py", line 885, in _do_insert
using=using, raw=raw)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/manager.py", line 127, in manager_method
return getattr(self.get_queryset(), name)(*args, **kwargs)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/query.py", line 920, in _insert
return query.get_compiler(using=using).execute_sql(return_id)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/models/sql/compiler.py", line 974, in execute_sql
cursor.execute(sql, params)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/utils.py", line 97, in __exit__
six.reraise(dj_exc_type, dj_exc_value, traceback)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/backends/utils.py", line 64, in execute
return self.cursor.execute(sql, params)
File "/home/ram/.virtual/helper/local/lib/python2.7/site-packages/django/db/backends/sqlite3/base.py", line 318, in execute
return Database.Cursor.execute(self, query, params)
IntegrityError: UNIQUE constraint failed: user_user.email, user_user.store_id
----------------------------------------------------------------------
Ran 1 test in 0.003s
FAILED (errors=1)
User model extends AbstractUser (nothing other added at User), which is as follow
class AbstractUser(auth_models.AbstractBaseUser, PermissionsMixin):
email = models.EmailField(_('email address'))
store = models.ForeignKey(Store, verbose_name=_('Store Name'), null=True)
first_name = models.CharField(_('First name'), max_length=255, blank=True)
last_name = models.CharField(_('Last name'), max_length=255, blank=True)
is_staff = models.BooleanField(
_('Staff status'), default=False,
help_text=_('Designates whether the user can log into this admin '
'site.'))
is_active = models.BooleanField(
_('Active'), default=True,
help_text=_('Designates whether this user should be treated as '
'active. Unselect this instead of deleting accounts.'))
date_joined = models.DateTimeField(_('date joined'),
default=timezone.now)
objects = UserManager()
USERNAME_FIELD = 'email'
REQUIRED_FIELDS = ['store']
class Meta:
abstract = True
verbose_name = _('User')
verbose_name_plural = _('Users')
unique_together = ('email', 'store')
and UserManager
class UserManager(auth_models.BaseUserManager):
def create_user(self, store, email, password=None, **extra_fields):
"""
Creates and saves a User with the given email and
password.
"""
now = timezone.now()
if not email:
raise ValueError('The given email must be set')
email = UserManager.normalize_email(email)
try:
with transaction.atomic():
store, created = Store.objects.get_or_create(name=store)
user = self.model(email=email, store=store, is_staff=False, is_active=True, is_superuser=False,
last_login=now, date_joined=now, **extra_fields)
user.set_password(password)
user.save(using=self._db)
except Error as e:
logging.ERROR(e)
raise Error("Internal Error: Unable to create user")
return user
def create_superuser(self, store, email, password, **extra_fields):
u = self.create_user(store, email, password, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = True
u.save(using=self._db)
return u
def create_staffuser(self, store, email, password, **extra_fields):
u = self.create_user(store, email, password, **extra_fields)
u.is_staff = True
u.is_active = True
u.is_superuser = False
u.save(using=self._db)
return u
Version: 1.8
So the error is being raised at the right line (in assertRaises
), but I suspect there are two different kinds of IntegrityError
classes at play here - one that is imported by the test, and one that is raised by the database backend.
e.g.: django.db.backends.postgresql.base.IntegrityError
is not the same as django.db.backends.sqlite3.base.IntegrityError
. On top of that, there is the Django exception wrapper django.db.utils.IntegrityError
The issue can be debugged and verified by using self.assertRaises
as a context manager:
with self.assertRaises(Exception) as raised: # top level exception as we want to figure out its exact type
user2.save()
self.assertEqual(IntegrityError, type(raised.exception)) # if it fails, we'll get the correct type to import
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With