from django.db import models
from django.template import defaultfilters
+from karmaworld.settings.manual_unique_together import auto_add_check_unique_together
+
class School(models.Model):
""" A grouping that contains many courses """
class Meta:
ordering = ['-file_count', 'school', 'name']
+ unique_together = ('school', 'name', 'instructor_name')
+ verbose_name = 'course'
+ verbose_name_plural = 'courses'
def __unicode__(self):
return u"{0}: {1}".format(self.name, self.school)
""" Update self.file_count by summing the note_set """
self.file_count = self.note_set.count()
self.save()
+
+# Enforce unique constraints even when we're using a database like
+# SQLite that doesn't understand them
+auto_add_check_unique_together(Course)
+
+from django.db import IntegrityError
from django.test import TestCase
from karmaworld.apps.courses.models import *
from django.test.client import Client
def testCourseUniqueness(self):
"""Make sure we can't create multiple courses with the same
school + course name + instructor name combination."""
- with self.assertRaises(Exception):
- Course.objects.create(name="Underwater Basketweaving", instructor_name="Alice Janney", school=self.harvard)
+ with self.assertRaises(IntegrityError):
+ Course.objects.create(name=self.course1.name, instructor_name=self.course1.instructor_name, school=self.course1.school)
+ self.assertEqual(Course.objects.count(), 1)
def testSchoolSlug(self):
self.assertEqual(self.harvard.slug, defaultfilters.slugify(self.harvard.name))
--- /dev/null
+from django.conf import settings
+from django.db.models import signals, FieldDoesNotExist
+from django.utils.text import get_text_list
+from django.db import IntegrityError
+from django.utils.translation import ugettext as _
+
+# This little gem is borrowed from
+# https://djangosnippets.org/snippets/1628/
+
+def check_unique_together(sender, **kwargs):
+ """
+ Check models unique_together manually. Django enforced unique together only the database level, but
+ some databases (e.g. SQLite) doesn't support this.
+
+ usage:
+ from django.db.models import signals
+ signals.pre_save.connect(check_unique_together, sender=MyModelClass)
+
+ or use auto_add_check_unique_together(), see below
+ """
+ instance = kwargs["instance"]
+ for field_names in sender._meta.unique_together:
+ model_kwargs = {}
+ for field_name in field_names:
+ try:
+ data = getattr(instance, field_name)
+ except FieldDoesNotExist:
+ # e.g.: a missing field, which is however necessary.
+ # The real exception on model creation should be raised.
+ continue
+ model_kwargs[field_name] = data
+
+ query_set = sender.objects.filter(**model_kwargs)
+ if instance.pk != None:
+ # Exclude the instance if it was saved in the past
+ query_set = query_set.exclude(pk=instance.pk)
+
+ count = query_set.count()
+ if count > 0:
+ field_names = get_text_list(field_names, _('and'))
+ msg = _(u"%(model_name)s with this %(field_names)s already exists.") % {
+ 'model_name': unicode(instance.__class__.__name__),
+ 'field_names': unicode(field_names)
+ }
+ raise IntegrityError(msg)
+
+def auto_add_check_unique_together(model_class):
+ """
+ Add only the signal handler check_unique_together, if a database without UNIQUE support is used.
+ """
+ if 'sqlite' in settings.DATABASES['default']['ENGINE']:
+ signals.pre_save.connect(check_unique_together, sender=model_class)
+