Metadata-Version: 2.1
Name: algoliasearch-django
Version: 1.7.0
Summary: Algolia Search integration for Django
Home-page: https://github.com/algolia/algoliasearch-django
Author: Algolia Team
Author-email: support@algolia.com
License: MIT License
Keywords: algolia,pyalgolia,search,backend,hosted,cloud,full-text search,faceted search,django
Platform: UNKNOWN
Classifier: Environment :: Web Environment
Classifier: Framework :: Django
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python
Classifier: Programming Language :: Python :: 2
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Internet :: WWW/HTTP
Requires-Dist: django (>=1.7)
Requires-Dist: algoliasearch

Algolia Search API Client for Django
====================================

`Algolia Search <https://www.algolia.com>`__ is a hosted full-text,
numerical, and faceted search engine capable of delivering realtime
results from the first keystroke.

`Build Status <https://travis-ci.org/algolia/algoliasearch-django>`__
`Coverage
Status <https://coveralls.io/r/algolia/algoliasearch-django>`__ `PyPI
version <http://badge.fury.io/py/algoliasearch-django>`__

This package lets you easily integrate the Algolia Search API to your
`Django <https://www.djangoproject.com/>`__ project. It’s based on the
`algoliasearch-client-python <https://github.com/algolia/algoliasearch-client-python>`__
package.

You might be interested in this sample Django application providing a
typeahead.js based auto-completion and Google-like instant search:
`algoliasearch-django-example <https://github.com/algolia/algoliasearch-django-example>`__

Compatible with **Python 2.7**, **Python 3.4+** and **Django 1.7+**

API Documentation
-----------------

You can find the full reference on `Algolia’s
website <https://www.algolia.com/doc/api-client/django/>`__.

1. `Setup <#setup>`__

   -  `Introduction <#introduction>`__
   -  `Install <#install>`__
   -  `Setup <#setup>`__
   -  `Quick Start <#quick-start>`__

2. `Commands <#commands>`__

   -  `Commands <#commands>`__

3. `Search <#search>`__

   -  `Search <#search>`__

4. `Geo-Search <#geo-search>`__

   -  `Geo-Search <#geo-search>`__

5. `Tags <#tags>`__

   -  `Tags <#tags>`__

6. `Options <#options>`__

   -  `Custom objectID <#custom-codeobjectidcode>`__
   -  `Custom index name <#custom-index-name>`__
   -  `Field Preprocessing and Related
      objects <#field-preprocessing-and-related-objects>`__
   -  `Index settings <#index-settings>`__
   -  `Restrict indexing to a subset of your
      data <#restrict-indexing-to-a-subset-of-your-data>`__
   -  `Multiple indices per model <#multiple-indices-per-model>`__

7. `Tests <#tests>`__

   -  `Run Tests <#run-tests>`__

Setup
=====

Introduction
------------

This package lets you easily integrate the Algolia Search API to your
`Django <https://www.djangoproject.com/>`__ project. It’s based on the
`algoliasearch-client-python <https://github.com/algolia/algoliasearch-client-python>`__
package.

You might be interested in this sample Django application providing a
typeahead.js based auto-completion and Google-like instant search:
`algoliasearch-django-example <https://github.com/algolia/algoliasearch-django-example>`__

Compatible with **Python 2.7**, **Python 3.4+** and **Django 1.7+**

Install
-------

.. code:: sh

   pip install algoliasearch-django

.. _setup-1:

Setup
-----

In your Django settings, add ``algoliasearch_django`` to
``INSTALLED_APPS`` and add these two settings:

.. code:: python

   ALGOLIA = {
       'APPLICATION_ID': 'MyAppID',
       'API_KEY': 'MyApiKey'
   }

There are several optional settings:

-  ``INDEX_PREFIX``: prefix all indexes. Use it to separate different
   applications, like ``site1_Products`` and ``site2_Products``.
-  ``INDEX_SUFFIX``: suffix all indexes. Use it to differentiate
   development and production environments, like ``Location_dev`` and
   ``Location_prod``.
-  ``AUTO_INDEXING``: automatically synchronize the models with Algolia
   (default to **True**).
-  ``RAISE_EXCEPTIONS``: raise exceptions on network errors instead of
   logging them (default to **settings.DEBUG**).

Quick Start
-----------

Create an ``index.py`` inside each application that contains the models
you want to index. Inside this file, call ``algoliasearch.register()``
for each of the models you want to index:

.. code:: python

   # index.py

   import algoliasearch_django as algoliasearch

   from .models import YourModel

   algoliasearch.register(YourModel)

By default, all the fields of your model will be used. You can configure
the index by creating a subclass of ``AlgoliaIndex`` and using the
``register`` decorator:

.. code:: python

   # index.py

   from algoliasearch_django import AlgoliaIndex
   from algoliasearch_django.decorators import register

   from .models import YourModel

   @register(YourModel)
   class YourModelIndex(AlgoliaIndex):
       fields = ('name', 'date')
       geo_field = 'location'
       settings = {'searchableAttributes': ['name']}
       index_name = 'my_index'

Commands
========

.. _commands-1:

Commands
--------

-  ``python manage.py algolia_reindex``: reindex all the registered
   models. This command will first send all the record to a temporary
   index and then moves it.

   -  you can pass ``--model`` parameter to reindex a given model

-  ``python manage.py algolia_applysettings``: (re)apply the index
   settings.
-  ``python manage.py algolia_clearindex``: clear the index

Search
======

.. _search-1:

Search
------

We recommend using our `InstantSearch.js
library <https://community.algolia.com/instantsearch.js>`__ to build
your search interface and perform search queries directly from the
end-user browser without going through your server.

However, if you want to search from your backend you can use the
``raw_search(YourModel, 'yourQuery', params)`` method. It retrieves the
raw JSON answer from the API, and accepts in ``param`` any `search
parameters <https://www.algolia.com/doc/api-reference/search-api-parameters/>`__.

.. code:: python

   from algoliasearch_django import raw_search

   params = { "hitsPerPage": 5 }
   response = raw_search(Contact, "jim", params)

Geo-Search
==========

.. _geo-search-1:

Geo-Search
----------

Use the ``geo_field`` attribute to localize your record. ``geo_field``
should be a callable that returns a tuple (latitude, longitude).

.. code:: python

   class Contact(models.model):
       name = models.CharField(max_lenght=20)
       lat = models.FloatField()
       lng = models.FloatField()

       def location(self):
           return (self.lat, self.lng)

   class ContactIndex(AlgoliaIndex):
       fields = 'name'
       geo_field = 'location'

   algoliasearch.register(Contact, ContactIndex)

Tags
====

.. _tags-1:

Tags
----

Use the ``tags`` attributes to add tags to your record. It can be a
field or a callable.

.. code:: python

   class ArticleIndex(AlgoliaIndex):
       tags = 'category'

At query time, specify ``{ tagFilters: 'tagvalue' }`` or
``{ tagFilters: ['tagvalue1', 'tagvalue2'] }`` as search parameters to
restrict the result set to specific tags.

Options
=======

Custom ``objectID``
-------------------

You can choose which field will be used as the ``objectID``. The field
should be unique and can be a string or integer. By default, we use the
``pk`` field of the model.

.. code:: python

   class ArticleIndex(AlgoliaIndex):
       custom_objectID = 'post_id'

Custom index name
-----------------

You can customize the index name. By default, the index name will be the
name of the model class.

.. code:: python

   class ContactIndex(algoliaindex):
       index_name = 'Enterprise'

Field Preprocessing and Related objects
---------------------------------------

If you want to process a field before indexing it (e.g. capitalizing a
``Contact``\ ’s ``name``), or if you want to index a `related
object <https://docs.djangoproject.com/en/1.11/ref/models/relations/>`__\ ’s
attribute, you need to define **proxy methods** for these fields.

Models
~~~~~~

.. code:: python

   class Account(models.Model):
       username = models.CharField(max_length=40)
       service = models.CharField(max_length=40)

   class Contact(models.Model):
       name = models.CharField(max_length=40)
       email = models.EmailField(max_length=60)
       //...
       accounts = models.ManyToManyField(Account)

       def account_names(self):
           return [str(account) for account in self.accounts.all()]

       def account_ids(self):
           return [account.id for account in self.accounts.all()]

Index
~~~~~

.. code:: python

   from algoliasearch_django import AlgoliaIndex

   class ContactIndex(AlgoliaIndex):
       fields = ('name', 'email', 'company', 'address', 'city', 'county',
                 'state', 'zip_code', 'phone', 'fax', 'web', 'followers', 'account_names', 'account_ids')

       settings = {
           'searchableAttributes': ['name', 'email', 'company', 'city', 'county', 'account_names',
           }

-  With this configuration, you can search for a ``Contact`` using its
   ``Account`` names
-  You can use the associated ``account_ids`` at search-time to fetch
   more data from your model (you should **only proxy the fields
   relevant for search** to keep your records’ size as small as
   possible)

Index settings
--------------

We provide many ways to configure your index allowing you to tune your
overall index relevancy. All the configuration is explained on `our
doc <https://www.algolia.com/doc/api-reference/api-parameters/>`__.

.. code:: python

   class ArticleIndex(AlgoliaIndex):
       settings = {
           'searchableAttributes': ['name', 'description', 'url'],
           'customRanking': ['desc(vote_count)', 'asc(name)']
       }

Restrict indexing to a subset of your data
------------------------------------------

You can add constraints controlling if a record must be indexed or not.
``should_index`` should be a callable that returns a boolean.

.. code:: python

   class Contact(models.model):
       name = models.CharField(max_lenght=20)
       age = models.IntegerField()

       def is_adult(self):
           return (self.age >= 18)

   class ContactIndex(AlgoliaIndex):
       should_index = 'is_adult'

Multiple indices per model
--------------------------

It is possible to have several indices for a single model.

-  First, define all your indices that you want for a model:

.. code:: python

   from django.contrib.algoliasearch import AlgoliaIndex

   class MyModelIndex1(AlgoliaIndex):
       name = 'MyModelIndex1'
       ...

   class MyModelIndex2(AlgoliaIndex):
       name = 'MyModelIndex2'
       ...

-  Then, define a meta model which will aggregate those indices:

.. code:: python

   class MyModelMetaIndex(AlgoliaIndex):
       def __init__(self, model, client, settings):
           self.indices = [
               MyModelIndex1(model, client, settings),
               MyModelIndex2(model, client, settings),
           ]

       def raw_search(self, query='', params=None):
           res = {}
           for index in self.indices:
               res[index.name] = index.raw_search(query, params)
           return res

       def update_records(self, qs, batch_size=1000, **kwargs):
           for index in self.indices:
               index.update_records(qs, batch_size, **kwargs)

       def reindex_all(self, batch_size=1000):
           for index in self.indices:
               index.reindex_all(batch_size)

       def set_settings(self):
           for index in self.indices:
               index.set_settings()

       def clear_index(self):
           for index in self.indices:
               index.clear_index()

       def save_record(self, instance, update_fields=None, **kwargs):
           for index in self.indices:
               index.save_record(instance, update_fields, **kwargs)

       def delete_record(self, instance):
           for index in self.indices:
               index.delete_record(instance)

-  Finally, register this ``AlgoliaIndex`` with your ``Model``:

.. code:: python

   import algoliasearch_django as algoliasearch
   algoliasearch.register(MyModel, MyModelMetaIndex)

Tests
=====

Run Tests
---------

To run the tests, first find your Algolia application id and Admin API
key (found on the Credentials page).

.. code:: shell

   ALGOLIA_APPLICATION_ID={APPLICATION_ID} ALGOLIA_API_KEY={ADMIN_API_KEY} tox

To override settings for some tests, use the `settings
method <https://docs.djangoproject.com/en/1.11/topics/testing/tools/#django.test.SimpleTestCase.settings>`__:

.. code:: python

   class OverrideSettingsTestCase(TestCase):
       def setUp(self):
           with self.settings(ALGOLIA={
               'APPLICATION_ID': 'foo',
               'API_KEY': 'bar',
               'AUTO_INDEXING': False
           }):
               algolia_engine.reset(settings.ALGOLIA)

       def tearDown(self):
           algolia_engine.reset(settings.ALGOLIA)

       def test_foo():
           # ...


