Skip to content

Commit 6a7078f

Browse files
committed
Merge branch 'release/0.7'
2 parents 1e80634 + 181bb26 commit 6a7078f

File tree

18 files changed

+289
-150
lines changed

18 files changed

+289
-150
lines changed

.travis.yml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@ python:
33
- "2.6"
44
- "2.7"
55
before_install:
6-
- export PIP_USE_MIRRORS=true
7-
- export PIP_INDEX_URL=https://simple.crate.io/
86
- export DJANGO_SETTINGS_MODULE=celery_haystack.test_settings
97
install:
108
- pip install -e .
@@ -15,10 +13,9 @@ script:
1513
- coverage run --branch --source=celery_haystack `which django-admin.py` test celery_haystack
1614
- coverage report --omit=celery_haystack/test*
1715
env:
18-
- DJANGO=1.3.1 HAYSTACK=v1
19-
- DJANGO=1.3.1 HAYSTACK=v2
20-
- DJANGO=1.4 HAYSTACK=v1
21-
- DJANGO=1.4 HAYSTACK=v2
22-
branches:
23-
only:
24-
- develop
16+
- DJANGO=1.3.7 HAYSTACK=v1
17+
- DJANGO=1.3.7 HAYSTACK=v2
18+
- DJANGO=1.4.5 HAYSTACK=v1
19+
- DJANGO=1.4.5 HAYSTACK=v2
20+
- DJANGO=1.5 HAYSTACK=v1
21+
- DJANGO=1.5 HAYSTACK=v2

AUTHORS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@ Josh Bohde
22
Germán M. Bravo
33
Jannis Leidel <[email protected]>
44
Daniel Lindsley
5+
Stefan Wehrmeyer

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Copyright (c) 2011-2012, Jannis Leidel and other contributors.
1+
Copyright (c) 2011-2013, Jannis Leidel and contributors.
22
All rights reserved.
33

44
Redistribution and use in source and binary forms, with or without modification,

MANIFEST.in

Lines changed: 0 additions & 3 deletions
This file was deleted.

README.rst

Lines changed: 62 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,73 @@ By default a few dependencies will automatically be installed:
4242
.. _`django-celery-transactions`: https://github.com/chrisdoble/django-celery-transactions
4343
.. _`Celery's user guide`: http://celery.readthedocs.org/en/latest/userguide/tasks.html#database-transactions
4444

45-
Setup
45+
Usage
4646
-----
4747

48-
1. Add ``'celery_haystack'`` to ``INSTALLED_APPS``.
48+
Haystack 1.X
49+
~~~~~~~~~~~~
50+
51+
1. Add ``'celery_haystack'`` to the ``INSTALLED_APPS`` setting
52+
53+
::
54+
55+
INSTALLED_APPS = [
56+
# ..
57+
'celery_haystack',
58+
]
59+
4960
2. Alter all of your ``SearchIndex`` subclasses to inherit from
50-
``celery_haystack.indexes.CelerySearchIndex`` (as well as
51-
``haystack.indexes.Indexable`` if you use Haystack `2.X`_).
61+
``celery_haystack.indexes.CelerySearchIndex``
62+
63+
::
64+
65+
from haystack import site
66+
from celery_haystack.indexes import CelerySearchIndex
67+
from myapp.models import Note
68+
69+
class NoteIndex(CelerySearchIndex):
70+
text = indexes.CharField(document=True, model_attr='content')
71+
72+
site.register(Note, NoteIndex)
73+
5274
3. Ensure your Celery instance is running.
5375

76+
Haystack 2.X
77+
~~~~~~~~~~~~
78+
79+
1. Add ``'celery_haystack'`` to the ``INSTALLED_APPS`` setting
80+
81+
::
82+
83+
INSTALLED_APPS = [
84+
# ..
85+
'celery_haystack',
86+
]
87+
88+
2. Enable the celery-haystack signal processor in the settings
89+
90+
::
91+
92+
HAYSTACK_SIGNAL_PROCESSOR = 'celery_haystack.signals.CelerySignalProcessor'
93+
94+
3. Alter all of your ``SearchIndex`` subclasses to inherit from
95+
``celery_haystack.indexes.CelerySearchIndex`` and
96+
``haystack.indexes.Indexable``
97+
98+
::
99+
100+
from haystack import indexes
101+
from celery_haystack.indexes import CelerySearchIndex
102+
from myapp.models import Note
103+
104+
class NoteIndex(CelerySearchIndex, indexes.Indexable):
105+
text = indexes.CharField(document=True, model_attr='content')
106+
107+
def get_model(self):
108+
return Note
109+
110+
4. Ensure your Celery instance is running.
111+
54112
Thanks
55113
------
56114

celery_haystack/__init__.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
1-
__version__ = '0.6.2'
1+
__version__ = '0.7'
2+
3+
4+
def version_hook(config):
5+
config['metadata']['version'] = __version__

celery_haystack/conf.py

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,32 @@
11
from django.conf import settings # noqa
2-
from haystack import constants
2+
from django.core.exceptions import ImproperlyConfigured
3+
from haystack import constants, __version__ as haystack_version
34
from appconf import AppConf
45

56

67
class CeleryHaystack(AppConf):
8+
#: The default alias to
79
DEFAULT_ALIAS = None
10+
#: The delay (in seconds) after which a failed index is retried
811
RETRY_DELAY = 5 * 60
12+
#: The number of retries that are done
913
MAX_RETRIES = 1
14+
#: The default Celery task class
1015
DEFAULT_TASK = 'celery_haystack.tasks.CeleryHaystackSignalHandler'
16+
#: Whether the task should be handled transaction safe
1117
TRANSACTION_SAFE = True
1218

19+
#: The batch size used by the CeleryHaystackUpdateIndex task
1320
COMMAND_BATCH_SIZE = None
21+
#: The max age of items used by the CeleryHaystackUpdateIndex task
1422
COMMAND_AGE = None
23+
#: Wehther to remove items from the index that aren't in the DB anymore
1524
COMMAND_REMOVE = False
25+
#: The number of multiprocessing workers used by the CeleryHaystackUpdateIndex task
1626
COMMAND_WORKERS = 0
27+
#: The names of apps to run update_index for
1728
COMMAND_APPS = []
29+
#: The verbosity level of the update_index call
1830
COMMAND_VERBOSITY = 1
1931

2032
def configure_default_alias(self, value):
@@ -28,3 +40,12 @@ def configure(self):
2840
value = int(value)
2941
data[name] = value
3042
return data
43+
44+
if (haystack_version[0] >= 2 and
45+
getattr(settings, 'HAYSTACK_SIGNAL_PROCESSOR', None) !=
46+
'celery_haystack.signals.CelerySignalProcessor'):
47+
48+
raise ImproperlyConfigured("When using celery-haystack with Haystack 2.X "
49+
"the HAYSTACK_SIGNAL_PROCESSOR setting must be "
50+
"set to 'celery_haystack.signals."
51+
"CelerySignalProcessor'.")

celery_haystack/indexes.py

Lines changed: 24 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from haystack import indexes
44
from haystack.utils import get_identifier
55

6-
from celery_haystack.utils import get_update_task
6+
from .utils import get_update_task
77

88

99
class CelerySearchIndex(indexes.SearchIndex):
@@ -14,44 +14,36 @@ class CelerySearchIndex(indexes.SearchIndex):
1414
def __init__(self, *args, **kwargs):
1515
super(CelerySearchIndex, self).__init__(*args, **kwargs)
1616
self.task_cls = get_update_task()
17-
self.has_get_model = hasattr(self, 'get_model')
18-
19-
def handle_model(self, model):
20-
if model is None and self.has_get_model:
21-
return self.get_model()
22-
return model
2317

2418
# We override the built-in _setup_* methods to connect the enqueuing
2519
# operation.
26-
def _setup_save(self, model=None):
27-
model = self.handle_model(model)
28-
signals.post_save.connect(self._enqueue_save, sender=model, dispatch_uid=CelerySearchIndex)
29-
30-
def _setup_delete(self, model=None):
31-
model = self.handle_model(model)
32-
signals.post_delete.connect(self._enqueue_delete, sender=model, dispatch_uid=CelerySearchIndex)
33-
34-
def _teardown_save(self, model=None):
35-
model = self.handle_model(model)
36-
signals.post_save.disconnect(self._enqueue_save, sender=model, dispatch_uid=CelerySearchIndex)
37-
38-
def _teardown_delete(self, model=None):
39-
model = self.handle_model(model)
40-
signals.post_delete.disconnect(self._enqueue_delete, sender=model, dispatch_uid=CelerySearchIndex)
41-
42-
def _enqueue_save(self, instance, **kwargs):
43-
if not getattr(instance, 'skip_indexing', False):
44-
self.enqueue_save(instance, **kwargs)
45-
46-
def _enqueue_delete(self, instance, **kwargs):
47-
if not getattr(instance, 'skip_indexing', False):
48-
self.enqueue_delete(instance, **kwargs)
20+
def _setup_save(self, model):
21+
signals.post_save.connect(self.enqueue_save,
22+
sender=model,
23+
dispatch_uid=CelerySearchIndex)
24+
25+
def _setup_delete(self, model):
26+
signals.post_delete.connect(self.enqueue_delete,
27+
sender=model,
28+
dispatch_uid=CelerySearchIndex)
29+
30+
def _teardown_save(self, model):
31+
signals.post_save.disconnect(self.enqueue_save,
32+
sender=model,
33+
dispatch_uid=CelerySearchIndex)
34+
35+
def _teardown_delete(self, model):
36+
signals.post_delete.disconnect(self.enqueue_delete,
37+
sender=model,
38+
dispatch_uid=CelerySearchIndex)
4939

5040
def enqueue_save(self, instance, **kwargs):
51-
return self.enqueue('update', instance)
41+
if not getattr(instance, 'skip_indexing', False):
42+
return self.enqueue('update', instance)
5243

5344
def enqueue_delete(self, instance, **kwargs):
54-
return self.enqueue('delete', instance)
45+
if not getattr(instance, 'skip_indexing', False):
46+
return self.enqueue('delete', instance)
5547

5648
def enqueue(self, action, instance):
5749
"""

celery_haystack/signals.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from django.db.models import signals
2+
3+
from haystack.signals import BaseSignalProcessor
4+
from haystack.utils import get_identifier
5+
from haystack.exceptions import NotHandled
6+
7+
from .utils import get_update_task
8+
from .indexes import CelerySearchIndex
9+
10+
11+
class CelerySignalProcessor(BaseSignalProcessor):
12+
13+
def setup(self):
14+
self.task_cls = get_update_task()
15+
signals.post_save.connect(self.enqueue_save)
16+
signals.post_delete.connect(self.enqueue_delete)
17+
18+
def teardown(self):
19+
signals.post_save.disconnect(self.enqueue_save)
20+
signals.post_delete.disconnect(self.enqueue_delete)
21+
22+
def enqueue_save(self, sender, instance, **kwargs):
23+
return self.enqueue('update', instance, sender, **kwargs)
24+
25+
def enqueue_delete(self, sender, instance, **kwargs):
26+
return self.enqueue('delete', instance, sender, **kwargs)
27+
28+
def enqueue(self, action, instance, sender, **kwargs):
29+
"""
30+
Given an individual model instance, determine if a backend
31+
handles the model, check if the index is Celery-enabled and
32+
enqueue task.
33+
"""
34+
using_backends = self.connection_router.for_write(instance=instance)
35+
36+
for using in using_backends:
37+
try:
38+
connection = self.connections[using]
39+
index = connection.get_unified_index().get_index(sender)
40+
except NotHandled:
41+
continue # Check next backend
42+
43+
if isinstance(index, CelerySearchIndex):
44+
if action == 'update' and not index.should_update(instance):
45+
continue
46+
self.task_cls.delay(action, get_identifier(instance))
47+
return # Only enqueue instance once

0 commit comments

Comments
 (0)