annotate custom_search/signals.py @ 887:9a15f7c27526

Actually save model object upon change. This commit was tested on the comments model. Additional logging added. Added check for Markdown image references. Added TODOs after observing behavior on comments.
author Brian Neal <bgneal@gmail.com>
date Tue, 03 Feb 2015 21:09:44 -0600
parents ad53d929281a
children
rev   line source
bgneal@753 1 """This module contains a custom Haystack signal processing class to update the
bgneal@753 2 search index in realtime. We update our search index by enqueuing edits and
bgneal@753 3 deletes into a queue for batch processing. Our class ensures we only enqueue
bgneal@753 4 content that should be in the search index.
bgneal@469 5
bgneal@469 6 """
bgneal@753 7 from django.db.models import signals
bgneal@753 8 import queued_search.signals
bgneal@469 9
bgneal@753 10 from bio.signals import profile_content_update
bgneal@753 11 from forums.signals import topic_content_update, post_content_update
bgneal@469 12
bgneal@753 13 import ygroup.models
bgneal@753 14 from weblinks.models import Link
bgneal@753 15 from podcast.models import Item
bgneal@753 16 from news.models import Story
bgneal@753 17 from downloads.models import Download
bgneal@753 18 from forums.models import Forum, Topic, Post
bgneal@753 19 from bio.models import UserProfile
bgneal@753 20
bgneal@753 21
bgneal@753 22 UID = 'custom_search.signals'
bgneal@753 23
bgneal@753 24
bgneal@753 25 class QueuedSignalProcessor(queued_search.signals.QueuedSignalProcessor):
bgneal@469 26 """
bgneal@753 27 This customized version of queued_search's QueuedSignalProcessor
bgneal@753 28 conditionally enqueues items to be indexed.
bgneal@469 29
bgneal@469 30 """
bgneal@753 31 def __init__(self, *args, **kwargs):
bgneal@753 32
bgneal@753 33 # We assume that it is okay to attempt to delete a model from the search
bgneal@753 34 # index even if the model object is not in the index. In other words,
bgneal@753 35 # attempting to delete an object from the index will not cause any
bgneal@753 36 # errors if it is not in the index. Thus if we see an object that has an
bgneal@753 37 # 'is_public' attribute, and it is false, we can safely enqueue a delete
bgneal@753 38 # in case the 'is_public' attribute just went from True to False. We
bgneal@753 39 # have no way of knowing that, it could have been False all along, but we
bgneal@753 40 # just try the delete in case to be safe.
bgneal@753 41
bgneal@753 42 # To make the code easier to read, use a table to drive our signal
bgneal@753 43 # connecting and disconnecting:
bgneal@753 44 self.signal_chain = [
bgneal@753 45 # Yahoo Group posts are always updated:
bgneal@753 46 (signals.post_save, ygroup.models.Post, self.enqueue_save),
bgneal@753 47 (signals.post_delete, ygroup.models.Post, self.enqueue_delete),
bgneal@753 48
bgneal@753 49 # Weblink Links are updated if they are public:
bgneal@753 50 (signals.post_save, Link, self.enqueue_public_save),
bgneal@753 51 (signals.post_delete, Link, self.enqueue_delete),
bgneal@753 52
bgneal@753 53 # Podcast Items are always updated:
bgneal@753 54 (signals.post_save, Item, self.enqueue_save),
bgneal@753 55 (signals.post_delete, Item, self.enqueue_delete),
bgneal@753 56
bgneal@753 57 # News Stories are always updated:
bgneal@753 58 (signals.post_save, Story, self.enqueue_save),
bgneal@753 59 (signals.post_delete, Story, self.enqueue_delete),
bgneal@753 60
bgneal@753 61 # Downloads are updated if they are public:
bgneal@753 62 (signals.post_save, Download, self.enqueue_public_save),
bgneal@753 63 (signals.post_delete, Download, self.enqueue_delete),
bgneal@753 64
bgneal@753 65 # Forum Topics are updated if they belong to a public forum:
bgneal@753 66 (topic_content_update, None, self.enqueue_topic_save),
bgneal@753 67 (signals.post_delete, Topic, self.enqueue_delete),
bgneal@753 68
bgneal@753 69 # Forum Posts are updated if they belong to a public forum:
bgneal@753 70 (post_content_update, None, self.enqueue_post_save),
bgneal@753 71 (signals.post_delete, Post, self.enqueue_delete),
bgneal@753 72
bgneal@753 73 # UserProfiles are updated when we receive a special signal:
bgneal@753 74 (profile_content_update, None, self.enqueue_profile),
bgneal@753 75 (signals.post_delete, UserProfile, self.enqueue_delete),
bgneal@753 76 ]
bgneal@753 77
bgneal@753 78 super(QueuedSignalProcessor, self).__init__(*args, **kwargs)
bgneal@753 79
bgneal@753 80 def setup(self):
bgneal@753 81 """We override setup() so we can attach signal handlers to only the
bgneal@753 82 models we search on. In some cases we have custom signals to tell us
bgneal@753 83 when to update the search index.
bgneal@469 84
bgneal@469 85 """
bgneal@753 86 for signal, sender, receiver in self.signal_chain:
bgneal@753 87 signal.connect(receiver, sender=sender, dispatch_uid=UID)
bgneal@469 88
bgneal@753 89 def teardown(self):
bgneal@753 90 """Disconnect all signals we previously connected."""
bgneal@753 91 for signal, sender, receiver in self.signal_chain:
bgneal@753 92 signal.disconnect(receiver, sender=sender, dispatch_uid=UID)
bgneal@753 93
bgneal@753 94 def enqueue_public_save(self, sender, instance, **kwargs):
bgneal@753 95 """Index only if the instance is_public.
bgneal@753 96
bgneal@753 97 If not, enqueue a delete just in case the is_public flag got flipped
bgneal@753 98 from True to False.
bgneal@469 99
bgneal@469 100 """
bgneal@753 101 if instance.is_public:
bgneal@753 102 self.enqueue_save(sender, instance, **kwargs)
bgneal@753 103 else:
bgneal@753 104 self.enqueue_delete(sender, instance, **kwargs)
bgneal@677 105
bgneal@753 106 def enqueue_topic_save(self, sender, **kwargs):
bgneal@753 107 """Enqueue only if the topic instance belongs to a public forum."""
bgneal@753 108 if sender.forum.id in Forum.objects.public_forum_ids():
bgneal@753 109 self.enqueue_save(Topic, sender, **kwargs)
bgneal@677 110
bgneal@753 111 def enqueue_post_save(self, sender, **kwargs):
bgneal@753 112 """Enqueue only if the post instance belongs to a public forum."""
bgneal@753 113 if sender.topic.forum.id in Forum.objects.public_forum_ids():
bgneal@753 114 self.enqueue_save(Post, sender, **kwargs)
bgneal@677 115
bgneal@753 116 def enqueue_profile(self, sender, **kwargs):
bgneal@753 117 """Forward the user profile instance on unconditionally."""
bgneal@753 118 self.enqueue_save(UserProfile, sender, **kwargs)