Skip to content

Search Tutorial

This tutorial walks through enabling search with Meilisearch, indexing data, and querying via GraphQL. It assumes Django + the auto GraphQL schema are enabled.

Step 1: Configure a backend

Add a search backend in settings.py:

GENERAL_MANAGER = {
    "SEARCH_BACKEND": {
        "class": "general_manager.search.backends.meilisearch.MeilisearchBackend",
        "options": {
            "url": "http://127.0.0.1:7700",
            "api_key": None,
        },
    }
}

Start Meilisearch locally:

docker run --rm -p 7700:7700 --name meilisearch \
  -e MEILI_NO_ANALYTICS=true \
  getmeili/meilisearch:v1.34.0

You can use other backends by swapping the backend class and options; ensure the backend is implemented and available in your environment.

Step 2: Add SearchConfig to a manager

Define searchable, filterable, and sortable fields:

from general_manager.search.config import IndexConfig

class Project(GeneralManager):
    class Interface(DatabaseInterface):
        name = CharField(max_length=200)
        status = CharField(max_length=50)

    class SearchConfig:
        indexes = [
            IndexConfig(
                name="global",
                fields=["name", "status"],
                filters=["status"],
                sorts=["name"],
            )
        ]

Step 3: Create index settings and reindex data

python manage.py search_index
python manage.py search_index --reindex

If you add or remove fields, filters, or sorts later, re-run with --reindex.

Step 4: Query via GraphQL

Example query:

query SearchProjects($filters: JSONString) {
  search(index: "global", query: "alpha", filters: $filters, sortBy: "name") {
    total
    results {
      __typename
      ... on ProjectType { id name status }
    }
  }
}

Variables:

{
  "filters": "{\"status\": \"public\"}"
}

Filters can also be passed as a list of filter items:

{
  "filters": "[{\"field\": \"status\", \"op\": \"in\", \"values\": [\"public\", \"draft\"]}]"
}

Step 5: Async indexing (optional)

Enable async updates via Celery:

GENERAL_MANAGER = {
    **GENERAL_MANAGER,
    "SEARCH_ASYNC": True,
}

Run a Celery worker so index updates can be dispatched. When async is disabled, updates run inline.

Step 6: Auto-reindex in development (optional)

The dev search backend is in-memory, so indexes are empty on every process start. To automatically reindex once per runserver process, enable:

GENERAL_MANAGER = {
    **GENERAL_MANAGER,
    "SEARCH_AUTO_REINDEX": True,
}

This runs search_index --reindex on the first request when DEBUG=True.

Step 7: Non-GraphQL usage

You can call the backend directly in Python:

from general_manager.search.backend_registry import get_search_backend

backend = get_search_backend()
result = backend.search("global", "alpha", filters={"status": "public"})

To reindex from code:

from general_manager.search.indexer import SearchIndexer

SearchIndexer().reindex_manager(Project)

Step 8: Production checklist

  • Pin your Meilisearch version and set MEILISEARCH_API_KEY.
  • Reindex after search schema changes.
  • Confirm filterable/sortable fields are configured.
  • Monitor indexing failures in logs and alert on task errors.