[bug 627781] Move object_id back into Watch and test for cascading deletes.

Also add missing migration (accidentally removed in previous commit).
This commit is contained in:
Paul Craciunoiu 2011-01-25 14:50:51 -08:00
Родитель ab3758b182
Коммит b812a931a9
5 изменённых файлов: 109 добавлений и 1 удалений

Просмотреть файл

@ -2,6 +2,7 @@ import hashlib
from django.db import models
from django.contrib.auth.models import User
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType
from sumo.models import ModelBase, LocaleField
@ -58,6 +59,8 @@ class Watch(ModelBase):
# Optional reference to a content type:
content_type = models.ForeignKey(ContentType, null=True, blank=True)
object_id = models.PositiveIntegerField(db_index=True, null=True)
content_object = generic.GenericForeignKey('content_type', 'object_id')
user = models.ForeignKey(User, null=True, blank=True)
@ -81,3 +84,15 @@ class WatchFilter(ModelBase):
# Either ints or hashes of enumerated strings. All we can't represent
# easily with this schema is arbitrary (open-vocab) strings.
value = models.IntegerField()
class NotificationsMixin(models.Model):
"""Mixin for notifications models that adds watches as a generic relation.
So we get cascading deletes for free, yay!
"""
watches = generic.GenericRelation(Watch)
class Meta(object):
abstract = True

Просмотреть файл

@ -1,4 +1,9 @@
from django.conf import settings
from django.core.management import call_command
from django.db.models import loading
from notifications.models import Watch, WatchFilter
from sumo.tests import TestCase
from users.tests import user
@ -21,3 +26,34 @@ def watch_filter(save=False, **kwargs):
if save:
f.save()
return f
class ModelsTestCase(TestCase):
"""Does some pre-setup and post-teardown work to create tables for any
of your test models.
Simply subclass this and set self.apps to a tuple of *additional*
installed apps. These will be added *after* the ones in
settings.INSTALLED_APPS.
Based on http://stackoverflow.com/questions/502916#1827272
"""
apps = []
def _pre_setup(self):
# Add the models to the db.
self._original_installed_apps = list(settings.INSTALLED_APPS)
for app in self.apps:
settings.INSTALLED_APPS.append(app)
loading.cache.loaded = False
call_command('syncdb', interactive=False, verbosity=0)
# Call the original method that does the fixtures etc.
super(ModelsTestCase, self)._pre_setup()
def _post_teardown(self):
# Call the original method.
super(ModelsTestCase, self)._post_teardown()
# Restore the settings.
settings.INSTALLED_APPS = self._original_installed_apps
loading.cache.loaded = False

Просмотреть файл

@ -0,0 +1,9 @@
from django.db import models
from notifications.models import NotificationsMixin
# TODO: figure out why placing the mixin *after* models.Model fails
# See also http://code.djangoproject.com/ticket/10249
class MockModel(NotificationsMixin, models.Model):
pass

Просмотреть файл

@ -4,7 +4,8 @@ from django.contrib.contenttypes.models import ContentType
from notifications.events import Event
from notifications.models import Watch
from notifications.tests import watch, watch_filter
from notifications.tests import watch, watch_filter, ModelsTestCase
from notifications.tests.models import MockModel
from sumo.tests import TestCase
from users.tests import user
@ -140,3 +141,21 @@ class TestNotification(TestCase):
FilteredContentTypeEvent.notify('hi@there.com', color=3, flavor=4)
assert not FilteredContentTypeEvent.is_notifying('hi@there.com',
color=3)
class TestCascadeDelete(ModelsTestCase):
"""Cascading deletes on object_id + content_type."""
apps = ['notifications.tests']
def test_mock_model(self):
"""Deleting an instance of MockModel should delete watches.
Create instance of MockModel from notifications.tests.models, then
delete it and watch the cascade go.
"""
mock_m = MockModel.objects.create()
watch(event_type=TYPE, email='hi@there.com', content_object=mock_m,
save=True)
MockModel.objects.all().delete()
assert not Watch.objects.count(), 'Cascade delete failed.'

Просмотреть файл

@ -0,0 +1,29 @@
CREATE TABLE `notifications_watch` (
`id` integer NOT NULL AUTO_INCREMENT,
`event_type` varchar(30) binary NOT NULL,
`content_type_id` integer DEFAULT NULL,
`object_id` integer unsigned DEFAULT NULL,
`user_id` integer DEFAULT NULL,
`email` varchar(75) DEFAULT NULL,
`secret` varchar(10) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `notifications_watch_2be07fce` (`event_type`),
KEY `notifications_watch_e4470c6e` (`content_type_id`),
KEY `notifications_watch_829e37fd` (`object_id`),
KEY `notifications_watch_fbfc09f1` (`user_id`),
KEY `notifications_watch_3904588a` (`email`),
CONSTRAINT `content_type_id_refs_id_23da5933` FOREIGN KEY (`content_type_id`) REFERENCES `django_content_type` (`id`),
CONSTRAINT `user_id_refs_id_2dc6eef1` FOREIGN KEY (`user_id`) REFERENCES `auth_user` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `notifications_watchfilter` (
`id` integer NOT NULL AUTO_INCREMENT,
`watch_id` integer NOT NULL,
`name` binary(20) NOT NULL,
`value` integer NOT NULL,
PRIMARY KEY (`id`),
KEY `notifications_watchfilter_6e1bd094` (`watch_id`),
KEY `notifications_watchfilter_52094d6e` (`name`),
CONSTRAINT `watch_id_refs_id_444d6e79` FOREIGN KEY (`watch_id`) REFERENCES `notifications_watch` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;