Name | django-meilisearch-indexer JSON |
Version |
1.0.1
JSON |
| download |
home_page | None |
Summary | Meilisearch indexer for django models and related utilities |
upload_time | 2024-11-02 14:14:41 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.9 |
license | MIT License Copyright (c) 2024 Jordan Kowal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
keywords |
django
meilisearch
indexer
|
VCS |
|
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
# ✨ Django Meilisearch Indexer ✨
![Code quality](https://github.com/Jordan-Kowal/django-meilisearch-indexer/actions/workflows/code_quality.yml/badge.svg?branch=main)
![Tests](https://github.com/Jordan-Kowal/django-meilisearch-indexer/actions/workflows/tests.yml/badge.svg?branch=main)
![Build](https://github.com/Jordan-Kowal/django-meilisearch-indexer/actions/workflows/publish_package.yml/badge.svg?event=release)
![Coverage](https://badgen.net/badge/coverage/%3E90%25/pink)
![Tag](https://badgen.net/badge/tag/1.0.1/orange)
![Python](https://badgen.net/badge/python/3.9%20|%203.10%20|%203.11%20|%203.12|%203.13)
![Licence](https://badgen.net/badge/licence/MIT)
- [✨ Django Meilisearch Indexer ✨](#-django-meilisearch-indexer-)
- [💻 How to install](#-how-to-install)
- [⚡ Quick start](#-quick-start)
- [📕 Available modules](#-available-modules)
- [🍜 Recipes](#-recipes)
- [Create indexes on boot](#create-indexes-on-boot)
- [Async actions with celery](#async-actions-with-celery)
- [Mock for testing](#mock-for-testing)
- [Admin actions](#admin-actions)
- [🔗 Useful links](#-useful-links)
Provides a `MeilisearchModelIndexer` class to easily index django models in Meilisearch.
## 💻 How to install
The package is available on PyPi with the name `django_meilisearch_indexer`.
Simply run:
```shell
pip install django_meilisearch_indexer
```
## ⚡ Quick start
Here's a basic example:
```python
# Imports
from typing import Any, Dict
from django.db import models
from django_meilisearch_indexer.indexers import MeilisearchModelIndexer
# Model
class Tag(models.Model):
name = models.CharField(max_length=100, unique=True)
color = models.CharField(max_length=100)
is_disabled = models.BooleanField(default=False)
# Indexer
class TagIndexer(MeilisearchModelIndexer[Tag]):
MODEL_CLASS = Tag
PRIMARY_KEY = "id"
SETTINGS = {
"filterableAttributes": ["is_disabled"],
"searchableAttributes": ["name"],
"sortableAttributes": ["name", "color"],
}
@classmethod
def build_object(cls, instance: Tag) -> Dict[str, Any]:
return {
"id": instance.id,
"name": instance.name,
"color": instance.color,
"is_disabled": instance.is_disabled,
}
@classmethod
def index_name(cls) -> str:
return "tags"
# Call
TagIndexer.maybe_create_index()
```
## 📕 Available modules
This library contains the following importable modules:
```python
# The main indexer
from django_meilisearch_indexer.indexers import MeilisearchModelIndexer
# Some serializers for your API
from django_meilisearch_indexer.serializers import (
MeilisearchOnlyHitsResponseSerializer,
MeilisearchSearchResultsSerializer,
MeilisearchSimpleSearchSerializer,
)
# Lots of typing classes
from django_meilisearch_indexer.types import (
Faceting,
MeilisearchFilters,
MeilisearchFilterValue,
MeilisearchSearchHits,
MeilisearchSearchParameters,
MeilisearchSearchResults,
MeilisearchSettings,
MinWordSizeForTypos,
Pagination,
Precision,
RankingRule,
TypoTolerance,
)
```
## 🍜 Recipes
### Create indexes on boot
Generate your indexes on boot using `AppConfig.ready()`.
```python
class TagConfig(AppConfig):
name = "tags"
def ready(self) -> None:
from django.conf import settings
from tags.indexers import TagIndexer
if settings.IS_RUNNING_MYPY or settings.ENVIRONMENT == "test":
return
TagIndexer.maybe_create_index()
```
### Async actions with celery
Make your indexation asynchronous using `celery` and `rabbitmq`.
```python
from typing import Dict, List
from celery import shared_task
from django.conf import settings
from django.db.models import Q
@shared_task(queue=settings.RABBITMQ_USER_QUEUE)
def index_tags(ids: List[int]) -> Dict[str, str]:
from tags.indexers import TagIndexer
TagIndexer.index_from_query(Q(pk__in=ids))
return {"result": "ok"}
# ...
index_tags.s(ids).apply_async(countdown=5)
```
### Mock for testing
For testing, you'll need to mock the following tasks:
```python
from unittest import TestCase
from unittest.mock import patch
class TagTestCase(TestCase):
def setUp(self) -> None:
super().setUp()
self._mock_indexers()
self._mock_celery_tasks()
def _mock_indexers(self) -> None:
"""
Patches the `index_name` functions of all indexers.
This allows running tests against a Meilisearch server
without overwriting the actual index.
"""
self.indexer_mocks = [
patch(
"tags.indexers.TagIndexer.index_name",
return_value="test_tags",
).start(),
]
# If you are using celery tasks
def _mock_celery_tasks(self) -> None:
"""Patches the celery tasks in both forms: `delay` and `apply_async`."""
names = [
"tags.tasks.index_tags.delay",
"tags.tasks.index_tags.apply_async",
]
self.celery_task_mocks = {name: patch(name).start() for name in names}
def test_something(self):
# ...
self.celery_task_mocks[
"tags.tasks.index_tags.apply_async"
].assert_called_once_with(([recipe.id],), {}, countdown=5)
# ...
```
### Admin actions
To trigger your indexations through the django admin interface,
you can add a custom action like so:
```python
from django.contrib import admin
from django.db.models import QuerySet
from django.http import HttpRequest, HttpResponseRedirect
from tags import tasks
from tags.models import Tag
@admin.action(description="[Meilisearch] Index selected item(s)")
def index_multiple(
model_admin: admin.ModelAdmin,
request: HttpRequest,
queryset: QuerySet,
) -> HttpResponseRedirect:
ids = list(queryset.values_list("id", flat=True))
model_admin.index_task.s(ids).apply_async(countdown=5)
model_admin.message_user(request, f"Indexing {len(ids)} items(s) on Meilisearch")
return HttpResponseRedirect(request.get_full_path())
class TagAdmin(admin.ModelAdmin):
index_task = tasks.index_tags
extra_actions = [index_multiple]
# ...
```
## 🔗 Useful links
- [Want to contribute?](CONTRIBUTING.md)
- [See what's new!](CHANGELOG.md)
Raw data
{
"_id": null,
"home_page": null,
"name": "django-meilisearch-indexer",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.9",
"maintainer_email": "Jordan Kowal <kowaljordan@gmail.com>",
"keywords": "django, meilisearch, indexer",
"author": null,
"author_email": "Jordan Kowal <kowaljordan@gmail.com>",
"download_url": "https://files.pythonhosted.org/packages/e5/b7/3708633a32d5642fa4f971b4eaa202534fa10cfdc60b24d3cfa39cc15dba/django_meilisearch_indexer-1.0.1.tar.gz",
"platform": null,
"description": "# \u2728 Django Meilisearch Indexer \u2728\n\n![Code quality](https://github.com/Jordan-Kowal/django-meilisearch-indexer/actions/workflows/code_quality.yml/badge.svg?branch=main)\n![Tests](https://github.com/Jordan-Kowal/django-meilisearch-indexer/actions/workflows/tests.yml/badge.svg?branch=main)\n![Build](https://github.com/Jordan-Kowal/django-meilisearch-indexer/actions/workflows/publish_package.yml/badge.svg?event=release)\n![Coverage](https://badgen.net/badge/coverage/%3E90%25/pink)\n![Tag](https://badgen.net/badge/tag/1.0.1/orange)\n![Python](https://badgen.net/badge/python/3.9%20|%203.10%20|%203.11%20|%203.12|%203.13)\n![Licence](https://badgen.net/badge/licence/MIT)\n\n- [\u2728 Django Meilisearch Indexer \u2728](#-django-meilisearch-indexer-)\n - [\ud83d\udcbb How to install](#-how-to-install)\n - [\u26a1 Quick start](#-quick-start)\n - [\ud83d\udcd5 Available modules](#-available-modules)\n - [\ud83c\udf5c Recipes](#-recipes)\n - [Create indexes on boot](#create-indexes-on-boot)\n - [Async actions with celery](#async-actions-with-celery)\n - [Mock for testing](#mock-for-testing)\n - [Admin actions](#admin-actions)\n - [\ud83d\udd17 Useful links](#-useful-links)\n\nProvides a `MeilisearchModelIndexer` class to easily index django models in Meilisearch.\n\n## \ud83d\udcbb How to install\n\nThe package is available on PyPi with the name `django_meilisearch_indexer`.\nSimply run:\n\n```shell\npip install django_meilisearch_indexer\n```\n\n## \u26a1 Quick start\n\nHere's a basic example:\n\n```python\n# Imports\nfrom typing import Any, Dict\nfrom django.db import models\nfrom django_meilisearch_indexer.indexers import MeilisearchModelIndexer\n\n# Model\nclass Tag(models.Model):\n name = models.CharField(max_length=100, unique=True)\n color = models.CharField(max_length=100)\n is_disabled = models.BooleanField(default=False)\n\n# Indexer\nclass TagIndexer(MeilisearchModelIndexer[Tag]):\n MODEL_CLASS = Tag\n PRIMARY_KEY = \"id\"\n SETTINGS = {\n \"filterableAttributes\": [\"is_disabled\"],\n \"searchableAttributes\": [\"name\"],\n \"sortableAttributes\": [\"name\", \"color\"],\n }\n\n @classmethod\n def build_object(cls, instance: Tag) -> Dict[str, Any]:\n return {\n \"id\": instance.id,\n \"name\": instance.name,\n \"color\": instance.color,\n \"is_disabled\": instance.is_disabled,\n }\n\n @classmethod\n def index_name(cls) -> str:\n return \"tags\"\n\n# Call\nTagIndexer.maybe_create_index()\n```\n\n## \ud83d\udcd5 Available modules\n\nThis library contains the following importable modules:\n\n```python\n# The main indexer\nfrom django_meilisearch_indexer.indexers import MeilisearchModelIndexer\n\n# Some serializers for your API\nfrom django_meilisearch_indexer.serializers import (\n MeilisearchOnlyHitsResponseSerializer,\n MeilisearchSearchResultsSerializer,\n MeilisearchSimpleSearchSerializer,\n)\n\n# Lots of typing classes\nfrom django_meilisearch_indexer.types import (\n Faceting,\n MeilisearchFilters,\n MeilisearchFilterValue,\n MeilisearchSearchHits,\n MeilisearchSearchParameters,\n MeilisearchSearchResults,\n MeilisearchSettings,\n MinWordSizeForTypos,\n Pagination,\n Precision,\n RankingRule,\n TypoTolerance,\n)\n```\n\n## \ud83c\udf5c Recipes\n\n### Create indexes on boot\n\nGenerate your indexes on boot using `AppConfig.ready()`.\n\n```python\nclass TagConfig(AppConfig):\n name = \"tags\"\n\n def ready(self) -> None:\n from django.conf import settings\n from tags.indexers import TagIndexer\n\n if settings.IS_RUNNING_MYPY or settings.ENVIRONMENT == \"test\":\n return\n\n TagIndexer.maybe_create_index()\n```\n\n### Async actions with celery\n\nMake your indexation asynchronous using `celery` and `rabbitmq`.\n\n```python\nfrom typing import Dict, List\nfrom celery import shared_task\nfrom django.conf import settings\nfrom django.db.models import Q\n\n@shared_task(queue=settings.RABBITMQ_USER_QUEUE)\ndef index_tags(ids: List[int]) -> Dict[str, str]:\n from tags.indexers import TagIndexer\n\n TagIndexer.index_from_query(Q(pk__in=ids))\n return {\"result\": \"ok\"}\n\n# ...\nindex_tags.s(ids).apply_async(countdown=5)\n```\n\n### Mock for testing\n\nFor testing, you'll need to mock the following tasks:\n\n```python\nfrom unittest import TestCase\nfrom unittest.mock import patch\n\nclass TagTestCase(TestCase):\n def setUp(self) -> None:\n super().setUp()\n self._mock_indexers()\n self._mock_celery_tasks()\n\n def _mock_indexers(self) -> None:\n \"\"\"\n Patches the `index_name` functions of all indexers.\n This allows running tests against a Meilisearch server\n without overwriting the actual index.\n \"\"\"\n self.indexer_mocks = [\n patch(\n \"tags.indexers.TagIndexer.index_name\",\n return_value=\"test_tags\",\n ).start(),\n ]\n\n # If you are using celery tasks\n def _mock_celery_tasks(self) -> None:\n \"\"\"Patches the celery tasks in both forms: `delay` and `apply_async`.\"\"\"\n names = [\n \"tags.tasks.index_tags.delay\",\n \"tags.tasks.index_tags.apply_async\",\n ]\n self.celery_task_mocks = {name: patch(name).start() for name in names}\n\n def test_something(self):\n # ...\n self.celery_task_mocks[\n \"tags.tasks.index_tags.apply_async\"\n ].assert_called_once_with(([recipe.id],), {}, countdown=5)\n # ...\n```\n\n### Admin actions\n\nTo trigger your indexations through the django admin interface,\nyou can add a custom action like so:\n\n```python\nfrom django.contrib import admin\nfrom django.db.models import QuerySet\nfrom django.http import HttpRequest, HttpResponseRedirect\nfrom tags import tasks\nfrom tags.models import Tag\n\n@admin.action(description=\"[Meilisearch] Index selected item(s)\")\ndef index_multiple(\n model_admin: admin.ModelAdmin,\n request: HttpRequest,\n queryset: QuerySet,\n) -> HttpResponseRedirect:\n ids = list(queryset.values_list(\"id\", flat=True))\n model_admin.index_task.s(ids).apply_async(countdown=5)\n model_admin.message_user(request, f\"Indexing {len(ids)} items(s) on Meilisearch\")\n return HttpResponseRedirect(request.get_full_path())\n\n\nclass TagAdmin(admin.ModelAdmin):\n index_task = tasks.index_tags\n extra_actions = [index_multiple]\n # ...\n```\n\n## \ud83d\udd17 Useful links\n\n- [Want to contribute?](CONTRIBUTING.md)\n- [See what's new!](CHANGELOG.md)\n",
"bugtrack_url": null,
"license": "MIT License Copyright (c) 2024 Jordan Kowal Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ",
"summary": "Meilisearch indexer for django models and related utilities",
"version": "1.0.1",
"project_urls": {
"Changelog": "https://github.com/Jordan-Kowal/django-meilisearch-indexer/blob/main/CHANGELOG.md",
"Issues": "https://github.com/Jordan-Kowal/django-meilisearch-indexer/issues",
"Release notes": "https://github.com/Jordan-Kowal/django-meilisearch-indexer/releases",
"Source": "https://github.com/Jordan-Kowal/django-meilisearch-indexer"
},
"split_keywords": [
"django",
" meilisearch",
" indexer"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "3c2fbd468bf36c01ffb2df7de03baa855f265ed8968ed413687b7189eaa2c344",
"md5": "7872c88e2a992e961edc3d9dc74c2b40",
"sha256": "845e6d03dd9a42a0a708328e8e728093720df51ab1e41b5b144f6a65ab6db62c"
},
"downloads": -1,
"filename": "django_meilisearch_indexer-1.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7872c88e2a992e961edc3d9dc74c2b40",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.9",
"size": 9604,
"upload_time": "2024-11-02T14:14:40",
"upload_time_iso_8601": "2024-11-02T14:14:40.157258Z",
"url": "https://files.pythonhosted.org/packages/3c/2f/bd468bf36c01ffb2df7de03baa855f265ed8968ed413687b7189eaa2c344/django_meilisearch_indexer-1.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "e5b73708633a32d5642fa4f971b4eaa202534fa10cfdc60b24d3cfa39cc15dba",
"md5": "dd3a4a3454fb6b325f67ce0ad5c8a234",
"sha256": "afca2aae987e8659dd167f11ec1a61757554cb208e5eee8526c7d8655ae234db"
},
"downloads": -1,
"filename": "django_meilisearch_indexer-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "dd3a4a3454fb6b325f67ce0ad5c8a234",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.9",
"size": 11352,
"upload_time": "2024-11-02T14:14:41",
"upload_time_iso_8601": "2024-11-02T14:14:41.767141Z",
"url": "https://files.pythonhosted.org/packages/e5/b7/3708633a32d5642fa4f971b4eaa202534fa10cfdc60b24d3cfa39cc15dba/django_meilisearch_indexer-1.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-11-02 14:14:41",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "Jordan-Kowal",
"github_project": "django-meilisearch-indexer",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "django-meilisearch-indexer"
}