Mercurial > public > sg101
comparison custom_search/receivers.py @ 924:78b459d4ab17
App refactor for custom_search for Django 1.7.7. upgrade.
This commit prevents a lot of Django warnings by creating our Haystack signal
processor as part of the custom_search apps' ready() method.
author | Brian Neal <bgneal@gmail.com> |
---|---|
date | Thu, 09 Apr 2015 19:43:07 -0500 |
parents | custom_search/signals.py@ad53d929281a |
children |
comparison
equal
deleted
inserted
replaced
923:bd043677d527 | 924:78b459d4ab17 |
---|---|
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 import haystack | |
10 | |
11 from bio.signals import profile_content_update | |
12 from forums.signals import topic_content_update, post_content_update | |
13 | |
14 import ygroup.models | |
15 from weblinks.models import Link | |
16 from podcast.models import Item | |
17 from news.models import Story | |
18 from downloads.models import Download | |
19 from forums.models import Forum, Topic, Post | |
20 from bio.models import UserProfile | |
21 | |
22 | |
23 UID = 'custom_search.signals' | |
24 | |
25 | |
26 class QueuedSignalProcessor(queued_search.signals.QueuedSignalProcessor): | |
27 """ | |
28 This customized version of queued_search's QueuedSignalProcessor | |
29 conditionally enqueues items to be indexed. | |
30 | |
31 """ | |
32 def __init__(self, *args, **kwargs): | |
33 | |
34 # We assume that it is okay to attempt to delete a model from the search | |
35 # index even if the model object is not in the index. In other words, | |
36 # attempting to delete an object from the index will not cause any | |
37 # errors if it is not in the index. Thus if we see an object that has an | |
38 # 'is_public' attribute, and it is false, we can safely enqueue a delete | |
39 # in case the 'is_public' attribute just went from True to False. We | |
40 # have no way of knowing that, it could have been False all along, but we | |
41 # just try the delete in case to be safe. | |
42 | |
43 # To make the code easier to read, use a table to drive our signal | |
44 # connecting and disconnecting: | |
45 self.signal_chain = [ | |
46 # Yahoo Group posts are always updated: | |
47 (signals.post_save, ygroup.models.Post, self.enqueue_save), | |
48 (signals.post_delete, ygroup.models.Post, self.enqueue_delete), | |
49 | |
50 # Weblink Links are updated if they are public: | |
51 (signals.post_save, Link, self.enqueue_public_save), | |
52 (signals.post_delete, Link, self.enqueue_delete), | |
53 | |
54 # Podcast Items are always updated: | |
55 (signals.post_save, Item, self.enqueue_save), | |
56 (signals.post_delete, Item, self.enqueue_delete), | |
57 | |
58 # News Stories are always updated: | |
59 (signals.post_save, Story, self.enqueue_save), | |
60 (signals.post_delete, Story, self.enqueue_delete), | |
61 | |
62 # Downloads are updated if they are public: | |
63 (signals.post_save, Download, self.enqueue_public_save), | |
64 (signals.post_delete, Download, self.enqueue_delete), | |
65 | |
66 # Forum Topics are updated if they belong to a public forum: | |
67 (topic_content_update, None, self.enqueue_topic_save), | |
68 (signals.post_delete, Topic, self.enqueue_delete), | |
69 | |
70 # Forum Posts are updated if they belong to a public forum: | |
71 (post_content_update, None, self.enqueue_post_save), | |
72 (signals.post_delete, Post, self.enqueue_delete), | |
73 | |
74 # UserProfiles are updated when we receive a special signal: | |
75 (profile_content_update, None, self.enqueue_profile), | |
76 (signals.post_delete, UserProfile, self.enqueue_delete), | |
77 ] | |
78 | |
79 super(QueuedSignalProcessor, self).__init__(*args, **kwargs) | |
80 | |
81 def setup(self): | |
82 """We override setup() so we can attach signal handlers to only the | |
83 models we search on. In some cases we have custom signals to tell us | |
84 when to update the search index. | |
85 | |
86 """ | |
87 for signal, sender, receiver in self.signal_chain: | |
88 signal.connect(receiver, sender=sender, dispatch_uid=UID) | |
89 | |
90 def teardown(self): | |
91 """Disconnect all signals we previously connected.""" | |
92 for signal, sender, receiver in self.signal_chain: | |
93 signal.disconnect(receiver, sender=sender, dispatch_uid=UID) | |
94 | |
95 def enqueue_public_save(self, sender, instance, **kwargs): | |
96 """Index only if the instance is_public. | |
97 | |
98 If not, enqueue a delete just in case the is_public flag got flipped | |
99 from True to False. | |
100 | |
101 """ | |
102 if instance.is_public: | |
103 self.enqueue_save(sender, instance, **kwargs) | |
104 else: | |
105 self.enqueue_delete(sender, instance, **kwargs) | |
106 | |
107 def enqueue_topic_save(self, sender, **kwargs): | |
108 """Enqueue only if the topic instance belongs to a public forum.""" | |
109 if sender.forum.id in Forum.objects.public_forum_ids(): | |
110 self.enqueue_save(Topic, sender, **kwargs) | |
111 | |
112 def enqueue_post_save(self, sender, **kwargs): | |
113 """Enqueue only if the post instance belongs to a public forum.""" | |
114 if sender.topic.forum.id in Forum.objects.public_forum_ids(): | |
115 self.enqueue_save(Post, sender, **kwargs) | |
116 | |
117 def enqueue_profile(self, sender, **kwargs): | |
118 """Forward the user profile instance on unconditionally.""" | |
119 self.enqueue_save(UserProfile, sender, **kwargs) | |
120 | |
121 | |
122 # Starting with Django 1.7, we'd see Django generate warnings if we defined | |
123 # a HAYSTACK_SIGNAL_PROCESSOR in our settings that referenced the class above. | |
124 # This is because Haystack creates an instance of our signal processor class | |
125 # (defined above) at import time, and thus imports this module very early in the | |
126 # application startup sequence. Warnings are then generated when this module | |
127 # imports our models, some of whose applications have not been imported yet. | |
128 # This problem will presumably go away when Haystack can fully support Django | |
129 # 1.7.x and implements an AppConfig with a ready() method. Until then, we don't | |
130 # use Haystack's signal processor object; we'll just create one here. This | |
131 # module will be imported when our custom_search app's ready() method runs. | |
132 | |
133 signal_processor = QueuedSignalProcessor(haystack.connections, | |
134 haystack.connection_router) |