comparison custom_search/signals.py @ 753:ad53d929281a

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