286 lines
9.9 KiB
ReStructuredText
286 lines
9.9 KiB
ReStructuredText
.. _ref-migration_from_1_to_2:
|
|
|
|
===========================================
|
|
Migrating From Haystack 1.X to Haystack 2.X
|
|
===========================================
|
|
|
|
Haystack introduced several backward-incompatible changes in the process of
|
|
moving from the 1.X series to the 2.X series. These were done to clean up the
|
|
API, to support new features & to clean up problems in 1.X. At a high level,
|
|
they consisted of:
|
|
|
|
* The removal of ``SearchSite`` & ``haystack.site``.
|
|
* The removal of ``handle_registrations`` & ``autodiscover``.
|
|
* The addition of multiple index support.
|
|
* The addition of ``SignalProcessors`` & the removal of ``RealTimeSearchIndex``.
|
|
* The removal/renaming of various settings.
|
|
|
|
This guide will help you make the changes needed to be compatible with Haystack
|
|
2.X.
|
|
|
|
|
|
Settings
|
|
========
|
|
|
|
Most prominently, the old way of specifying a backend & its settings has changed
|
|
to support the multiple index feature. A complete Haystack 1.X example might
|
|
look like::
|
|
|
|
HAYSTACK_SEARCH_ENGINE = 'solr'
|
|
HAYSTACK_SOLR_URL = 'http://localhost:9001/solr/default'
|
|
HAYSTACK_SOLR_TIMEOUT = 60 * 5
|
|
HAYSTACK_INCLUDE_SPELLING = True
|
|
HAYSTACK_BATCH_SIZE = 100
|
|
|
|
# Or...
|
|
HAYSTACK_SEARCH_ENGINE = 'whoosh'
|
|
HAYSTACK_WHOOSH_PATH = '/home/search/whoosh_index'
|
|
HAYSTACK_WHOOSH_STORAGE = 'file'
|
|
HAYSTACK_WHOOSH_POST_LIMIT = 128 * 1024 * 1024
|
|
HAYSTACK_INCLUDE_SPELLING = True
|
|
HAYSTACK_BATCH_SIZE = 100
|
|
|
|
# Or...
|
|
HAYSTACK_SEARCH_ENGINE = 'xapian'
|
|
HAYSTACK_XAPIAN_PATH = '/home/search/xapian_index'
|
|
HAYSTACK_INCLUDE_SPELLING = True
|
|
HAYSTACK_BATCH_SIZE = 100
|
|
|
|
In Haystack 2.X, you can now supply as many backends as you like, so all of the
|
|
above settings can now be active at the same time. A translated set of settings
|
|
would look like::
|
|
|
|
HAYSTACK_CONNECTIONS = {
|
|
'default': {
|
|
'ENGINE': 'haystack.backends.solr_backend.SolrEngine',
|
|
'URL': 'http://localhost:9001/solr/default',
|
|
'TIMEOUT': 60 * 5,
|
|
'INCLUDE_SPELLING': True,
|
|
'BATCH_SIZE': 100,
|
|
},
|
|
'autocomplete': {
|
|
'ENGINE': 'haystack.backends.whoosh_backend.WhooshEngine',
|
|
'PATH': '/home/search/whoosh_index',
|
|
'STORAGE': 'file',
|
|
'POST_LIMIT': 128 * 1024 * 1024,
|
|
'INCLUDE_SPELLING': True,
|
|
'BATCH_SIZE': 100,
|
|
},
|
|
'slave': {
|
|
'ENGINE': 'xapian_backend.XapianEngine',
|
|
'PATH': '/home/search/xapian_index',
|
|
'INCLUDE_SPELLING': True,
|
|
'BATCH_SIZE': 100,
|
|
},
|
|
}
|
|
|
|
You are required to have at least one connection listed within
|
|
``HAYSTACK_CONNECTIONS``, it must be named ``default`` & it must have a valid
|
|
``ENGINE`` within it. Bare minimum looks like::
|
|
|
|
HAYSTACK_CONNECTIONS = {
|
|
'default': {
|
|
'ENGINE': 'haystack.backends.simple_backend.SimpleEngine'
|
|
}
|
|
}
|
|
|
|
The key for each backend is an identifier you use to describe the backend within
|
|
your app. You should refer to the :ref:`ref-multiple_index` documentation for
|
|
more information on using the new multiple indexes & routing features.
|
|
|
|
Also note that the ``ENGINE`` setting has changed from a lowercase "short name"
|
|
of the engine to a full path to a new ``Engine`` class within the backend.
|
|
Available options are:
|
|
|
|
* ``haystack.backends.solr_backend.SolrEngine``
|
|
* ``haystack.backends.whoosh_backend.WhooshEngine``
|
|
* ``haystack.backends.simple_backend.SimpleEngine``
|
|
|
|
Additionally, the following settings were outright removed & will generate
|
|
an exception if found:
|
|
|
|
* ``HAYSTACK_SITECONF`` - Remove this setting & the file it pointed to.
|
|
* ``HAYSTACK_ENABLE_REGISTRATIONS``
|
|
* ``HAYSTACK_INCLUDE_SPELLING``
|
|
|
|
|
|
Backends
|
|
========
|
|
|
|
The ``dummy`` backend was outright removed from Haystack, as it served very
|
|
little use after the ``simple`` (pure-ORM-powered) backend was introduced.
|
|
|
|
If you wrote a custom backend, please refer to the "Custom Backends" section
|
|
below.
|
|
|
|
|
|
Indexes
|
|
=======
|
|
|
|
The other major changes affect the ``SearchIndex`` class. As the concept of
|
|
``haystack.site`` & ``SearchSite`` are gone, you'll need to modify your indexes.
|
|
|
|
A Haystack 1.X index might've looked like::
|
|
|
|
import datetime
|
|
from haystack.indexes import *
|
|
from haystack import site
|
|
from myapp.models import Note
|
|
|
|
|
|
class NoteIndex(SearchIndex):
|
|
text = CharField(document=True, use_template=True)
|
|
author = CharField(model_attr='user')
|
|
pub_date = DateTimeField(model_attr='pub_date')
|
|
|
|
def get_queryset(self):
|
|
"""Used when the entire index for model is updated."""
|
|
return Note.objects.filter(pub_date__lte=datetime.datetime.now())
|
|
|
|
|
|
site.register(Note, NoteIndex)
|
|
|
|
A converted Haystack 2.X index should look like::
|
|
|
|
import datetime
|
|
from haystack import indexes
|
|
from myapp.models import Note
|
|
|
|
|
|
class NoteIndex(indexes.SearchIndex, indexes.Indexable):
|
|
text = indexes.CharField(document=True, use_template=True)
|
|
author = indexes.CharField(model_attr='user')
|
|
pub_date = indexes.DateTimeField(model_attr='pub_date')
|
|
|
|
def get_model(self):
|
|
return Note
|
|
|
|
def index_queryset(self, using=None):
|
|
"""Used when the entire index for model is updated."""
|
|
return self.get_model().objects.filter(pub_date__lte=datetime.datetime.now())
|
|
|
|
Note the import on ``site`` & the registration statements are gone. Newly added
|
|
are is the ``NoteIndex.get_model`` method. This is a **required** method &
|
|
should simply return the ``Model`` class the index is for.
|
|
|
|
There's also a new, additional class added to the ``class`` definition. The
|
|
``indexes.Indexable`` class is a simple mixin that serves to identify the
|
|
classes Haystack should automatically discover & use. If you have a custom
|
|
base class (say ``QueuedSearchIndex``) that other indexes inherit from, simply
|
|
leave the ``indexes.Indexable`` off that declaration & Haystack won't try to
|
|
use it.
|
|
|
|
Additionally, the name of the ``document=True`` field is now enforced to be
|
|
``text`` across all indexes. If you need it named something else, you should
|
|
set the ``HAYSTACK_DOCUMENT_FIELD`` setting. For example::
|
|
|
|
HAYSTACK_DOCUMENT_FIELD = 'pink_polka_dot'
|
|
|
|
Finally, the ``index_queryset`` method should supplant the ``get_queryset``
|
|
method. This was present in the Haystack 1.2.X series (with a deprecation warning
|
|
in 1.2.4+) but has been removed in Haystack v2.
|
|
|
|
Finally, if you were unregistering other indexes before, you should make use of
|
|
the new ``EXCLUDED_INDEXES`` setting available in each backend's settings. It
|
|
should be a list of strings that contain the Python import path to the indexes
|
|
that should not be loaded & used. For example::
|
|
|
|
HAYSTACK_CONNECTIONS = {
|
|
'default': {
|
|
'ENGINE': 'haystack.backends.solr_backend.SolrEngine',
|
|
'URL': 'http://localhost:9001/solr/default',
|
|
'EXCLUDED_INDEXES': [
|
|
# Imagine that these indexes exist. They don't.
|
|
'django.contrib.auth.search_indexes.UserIndex',
|
|
'third_party_blog_app.search_indexes.EntryIndex',
|
|
]
|
|
}
|
|
}
|
|
|
|
This allows for reliable swapping of the index that handles a model without
|
|
relying on correct import order.
|
|
|
|
|
|
Removal of ``RealTimeSearchIndex``
|
|
==================================
|
|
|
|
Use of the ``haystack.indexes.RealTimeSearchIndex`` is no longer valid. It has
|
|
been removed in favor of ``RealtimeSignalProcessor``. To migrate, first change
|
|
the inheritance of all your ``RealTimeSearchIndex`` subclasses to use
|
|
``SearchIndex`` instead::
|
|
|
|
# Old.
|
|
class MySearchIndex(indexes.RealTimeSearchIndex, indexes.Indexable):
|
|
# ...
|
|
|
|
|
|
# New.
|
|
class MySearchIndex(indexes.SearchIndex, indexes.Indexable):
|
|
# ...
|
|
|
|
Then update your settings to enable use of the ``RealtimeSignalProcessor``::
|
|
|
|
HAYSTACK_SIGNAL_PROCESSOR = 'haystack.signals.RealtimeSignalProcessor'
|
|
|
|
|
|
Done!
|
|
=====
|
|
|
|
For most basic uses of Haystack, this is all that is necessary to work with
|
|
Haystack 2.X. You should rebuild your index if needed & test your new setup.
|
|
|
|
|
|
Advanced Uses
|
|
=============
|
|
|
|
Swapping Backend
|
|
----------------
|
|
|
|
If you were manually swapping the ``SearchQuery`` or ``SearchBackend`` being
|
|
used by ``SearchQuerySet`` in the past, it's now preferable to simply setup
|
|
another connection & use the ``SearchQuerySet.using`` method to select that
|
|
connection instead.
|
|
|
|
Also, if you were manually instantiating ``SearchBackend`` or ``SearchQuery``,
|
|
it's now preferable to rely on the connection's engine to return the right
|
|
thing. For example::
|
|
|
|
from haystack import connections
|
|
backend = connections['default'].get_backend()
|
|
query = connections['default'].get_query()
|
|
|
|
|
|
Custom Backends
|
|
---------------
|
|
|
|
If you had written a custom ``SearchBackend`` and/or custom ``SearchQuery``,
|
|
there's a little more work needed to be Haystack 2.X compatible.
|
|
|
|
You should, but don't have to, rename your ``SearchBackend`` & ``SearchQuery``
|
|
classes to be more descriptive/less collide-y. For example,
|
|
``solr_backend.SearchBackend`` became ``solr_backend.SolrSearchBackend``. This
|
|
prevents non-namespaced imports from stomping on each other.
|
|
|
|
You need to add a new class to your backend, subclassing ``BaseEngine``. This
|
|
allows specifying what ``backend`` & ``query`` should be used on a connection
|
|
with less duplication/naming trickery. It goes at the bottom of the file (so
|
|
that the classes are defined above it) and should look like::
|
|
|
|
from haystack.backends import BaseEngine
|
|
from haystack.backends.solr_backend import SolrSearchQuery
|
|
|
|
# Code then...
|
|
|
|
class MyCustomSolrEngine(BaseEngine):
|
|
# Use our custom backend.
|
|
backend = MySolrBackend
|
|
# Use the built-in Solr query.
|
|
query = SolrSearchQuery
|
|
|
|
Your ``HAYSTACK_CONNECTIONS['default']['ENGINE']`` should then point to the
|
|
full Python import path to your new ``BaseEngine`` subclass.
|
|
|
|
Finally, you will likely have to adjust the ``SearchBackend.__init__`` &
|
|
``SearchQuery.__init__``, as they have changed significantly. Please refer to
|
|
the commits for those backends.
|