[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.db import models
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.contenttypes import generic
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from sumo.models import ModelBase, LocaleField from sumo.models import ModelBase, LocaleField
@ -58,6 +59,8 @@ class Watch(ModelBase):
# Optional reference to a content type: # Optional reference to a content type:
content_type = models.ForeignKey(ContentType, null=True, blank=True) 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) 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 # Either ints or hashes of enumerated strings. All we can't represent
# easily with this schema is arbitrary (open-vocab) strings. # easily with this schema is arbitrary (open-vocab) strings.
value = models.IntegerField() 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 notifications.models import Watch, WatchFilter
from sumo.tests import TestCase
from users.tests import user from users.tests import user
@ -21,3 +26,34 @@ def watch_filter(save=False, **kwargs):
if save: if save:
f.save() f.save()
return f 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.events import Event
from notifications.models import Watch 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 sumo.tests import TestCase
from users.tests import user from users.tests import user
@ -140,3 +141,21 @@ class TestNotification(TestCase):
FilteredContentTypeEvent.notify('hi@there.com', color=3, flavor=4) FilteredContentTypeEvent.notify('hi@there.com', color=3, flavor=4)
assert not FilteredContentTypeEvent.is_notifying('hi@there.com', assert not FilteredContentTypeEvent.is_notifying('hi@there.com',
color=3) 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;