django-eose


Namedjango-eose JSON
Version 0.3.2 PyPI version JSON
download
home_pageNone
SummaryDjango Encrypted Object Search Engine.
upload_time2025-09-13 22:21:59
maintainerNone
docs_urlNone
authorNone
requires_python>=3.10
licenseMIT
keywords django search multiprocessing decrypted cache
VCS
bugtrack_url
requirements asgiref cffi cryptography Django psutil pycparser python-dotenv setuptools sqlparse wheel
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Django EOSE

**Django Encrypted Object Search Engine**  
An efficient search engine for encrypted fields in Django querysets, with support for parallel processing, smart batching, and result caching.

`django-eose` is ideal for scenarios where you need to search data that is encrypted in the database, providing high performance even on large datasets.

---

## Key Features

- **Parallel Search:** supports execution using processes, threads, or synchronous mode.  
- **Smart Batching:** batch size automatically adapts to available memory.  
- **Related Field Search:** search can be performed on fields of related objects, e.g., `order__client`.  
- **Result Caching:** frequently searched results are cached for faster repeated queries.  
- **Optimized for Large Datasets:** particularly useful for large datasets and encrypted fields.

---

## Installation

Install easily via `pip`:

```bash
pip install django-eose
```

## Requirements

- Python 3.10 or higher
- Django 5.2.5
- sqlparse==0.5.3
- asgiref==3.9.1
- psutil==7.0.0
- cffi==1.17.1
- cryptography==45.0.6
- pycparser==2.22

## Model Configuration

There are two ways to use django-eose. The first is to let django-eose handle the decryption itself using Fernet, which is much faster. The second is to create Getters in Django that already return the decrypted values. If you are going to use the first option, skip this step.

Example model using Fernet encryption:

```python
from django.db import models
from cryptography.fernet import Fernet

AES_KEY = b"<your_key_here>"

class Client(models.Model):
    _encrypted_name = models.BinaryField()
    _encrypted_email = models.BinaryField()

    # Method to decrypt
    def _decrypt_field(self, encrypted_value):
        return Fernet(AES_KEY).decrypt(encrypted_value).decode()

    # Method to encrypt
    def _encrypt_field(self, value):
        return Fernet(AES_KEY).encrypt(value.encode())
    
    # Creates properties that handle encryption/decryption
    @staticmethod
    def _property(field_name):
        def getter(self):
            return self._decrypt_field(getattr(self, field_name))
        
        def setter(self, value):
            setattr(self, field_name, self._encrypt_field(value))

        return property(getter, setter)
    
    # Fields accessible as normal attributes
    name = _property('_encrypted_name')
    email = _property('_encrypted_email')

```
⚠️ You interact with name and email like regular fields, while encryption/decryption happens transparently.

## Usage

Add AES_PASSWORD to your .env file:
```bash
AES_PASSWORD=your-password-here
```

To decrypt data in django-eose and speed up the process, use:

```python
from django_eose import search_queryset
from orders.models import OrderItem

# Example: search for "john" in related client fields
results = search_queryset(
    search="john",
    queryset=OrderItem.objects.all(),
    related_field="order__client",
    fields=("_encrypted_name", "_encrypted_email"),
    executor="processes",
    max_batch_size=1_000_000,
    decrypt=True
) # returns queryset.filter(pk__in=matched_ids)
```

To use the decrypted data returned by getters in Django, use:


```python
from django_eose import search_queryset
from orders.models import OrderItem

# Example: search for "john" in related client fields
results = search_queryset(
    search="john",
    queryset=OrderItem.objects.all(),
    related_field="order__client",
    fields=("name", "email"),
    only_fields=("_encrypted_name", "_encrypted_email"),
    executor="processes",
    max_batch_size=1_000_000
) # returns queryset.filter(pk__in=matched_ids)
```

## `search_queryset` Parameters

- search: search term (case-insensitive).
- queryset: Django queryset to search in.
- related_field: path to a related object using __ notation. (optional)
- fields: fields of the object to inspect.
- only_fields: fields to load with .only() for optimization (optional).
- executor: "processes", "threads", or "sync" (default: "processes").
- cache_timeout: cache duration in seconds (default: 600).
- imap_chunksize: chunk size per worker (default: 10240).
- memory_fraction: fraction of available memory for batching (default: 0.60).
- avg_obj_size_bytes: estimated average object size in bytes (optional).
- max_workers: maximum number of parallel workers (optional).
- max_batch_size: maximum number of objects per batch. (default: 1_000_000)
- decrypt: decrypt data using Fernet. (ignores the only_fields parameter)

Refer to `search_queryset` for full parameter details.

## Default Settings

`django-eose` defines default settings in `django_eose/settings.py`:

- MEMORY_FRACTION
- IMAP_CHUNKSIZE
- EXECUTOR
- CACHE_TIMEOUT
- AVG_OBJ_SIZE_FALLBACK
- MIN_BATCH_SIZE
- MAX_BATCH_SIZE

## License

MIT © 2025 Paulo Otávio Castoldi

## Links

[Source](https://github.com/paulootaviodev/django-eose)

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "django-eose",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.10",
    "maintainer_email": null,
    "keywords": "django, search, multiprocessing, decrypted, cache",
    "author": null,
    "author_email": "Paulo Ot\u00e1vio Castoldi <paulootavio343@outlook.com>",
    "download_url": "https://files.pythonhosted.org/packages/df/d9/7d88d04ce018655c5dfa3708206c4eba6cc8ab2880095db3e51039f27eca/django_eose-0.3.2.tar.gz",
    "platform": null,
    "description": "# Django EOSE\n\n**Django Encrypted Object Search Engine**  \nAn efficient search engine for encrypted fields in Django querysets, with support for parallel processing, smart batching, and result caching.\n\n`django-eose` is ideal for scenarios where you need to search data that is encrypted in the database, providing high performance even on large datasets.\n\n---\n\n## Key Features\n\n- **Parallel Search:** supports execution using processes, threads, or synchronous mode.  \n- **Smart Batching:** batch size automatically adapts to available memory.  \n- **Related Field Search:** search can be performed on fields of related objects, e.g., `order__client`.  \n- **Result Caching:** frequently searched results are cached for faster repeated queries.  \n- **Optimized for Large Datasets:** particularly useful for large datasets and encrypted fields.\n\n---\n\n## Installation\n\nInstall easily via `pip`:\n\n```bash\npip install django-eose\n```\n\n## Requirements\n\n- Python 3.10 or higher\n- Django 5.2.5\n- sqlparse==0.5.3\n- asgiref==3.9.1\n- psutil==7.0.0\n- cffi==1.17.1\n- cryptography==45.0.6\n- pycparser==2.22\n\n## Model Configuration\n\nThere are two ways to use django-eose. The first is to let django-eose handle the decryption itself using Fernet, which is much faster. The second is to create Getters in Django that already return the decrypted values. If you are going to use the first option, skip this step.\n\nExample model using Fernet encryption:\n\n```python\nfrom django.db import models\nfrom cryptography.fernet import Fernet\n\nAES_KEY = b\"<your_key_here>\"\n\nclass Client(models.Model):\n    _encrypted_name = models.BinaryField()\n    _encrypted_email = models.BinaryField()\n\n    # Method to decrypt\n    def _decrypt_field(self, encrypted_value):\n        return Fernet(AES_KEY).decrypt(encrypted_value).decode()\n\n    # Method to encrypt\n    def _encrypt_field(self, value):\n        return Fernet(AES_KEY).encrypt(value.encode())\n    \n    # Creates properties that handle encryption/decryption\n    @staticmethod\n    def _property(field_name):\n        def getter(self):\n            return self._decrypt_field(getattr(self, field_name))\n        \n        def setter(self, value):\n            setattr(self, field_name, self._encrypt_field(value))\n\n        return property(getter, setter)\n    \n    # Fields accessible as normal attributes\n    name = _property('_encrypted_name')\n    email = _property('_encrypted_email')\n\n```\n\u26a0\ufe0f You interact with name and email like regular fields, while encryption/decryption happens transparently.\n\n## Usage\n\nAdd AES_PASSWORD to your .env file:\n```bash\nAES_PASSWORD=your-password-here\n```\n\nTo decrypt data in django-eose and speed up the process, use:\n\n```python\nfrom django_eose import search_queryset\nfrom orders.models import OrderItem\n\n# Example: search for \"john\" in related client fields\nresults = search_queryset(\n    search=\"john\",\n    queryset=OrderItem.objects.all(),\n    related_field=\"order__client\",\n    fields=(\"_encrypted_name\", \"_encrypted_email\"),\n    executor=\"processes\",\n    max_batch_size=1_000_000,\n    decrypt=True\n) # returns queryset.filter(pk__in=matched_ids)\n```\n\nTo use the decrypted data returned by getters in Django, use:\n\n\n```python\nfrom django_eose import search_queryset\nfrom orders.models import OrderItem\n\n# Example: search for \"john\" in related client fields\nresults = search_queryset(\n    search=\"john\",\n    queryset=OrderItem.objects.all(),\n    related_field=\"order__client\",\n    fields=(\"name\", \"email\"),\n    only_fields=(\"_encrypted_name\", \"_encrypted_email\"),\n    executor=\"processes\",\n    max_batch_size=1_000_000\n) # returns queryset.filter(pk__in=matched_ids)\n```\n\n## `search_queryset` Parameters\n\n- search: search term (case-insensitive).\n- queryset: Django queryset to search in.\n- related_field: path to a related object using __ notation. (optional)\n- fields: fields of the object to inspect.\n- only_fields: fields to load with .only() for optimization (optional).\n- executor: \"processes\", \"threads\", or \"sync\" (default: \"processes\").\n- cache_timeout: cache duration in seconds (default: 600).\n- imap_chunksize: chunk size per worker (default: 10240).\n- memory_fraction: fraction of available memory for batching (default: 0.60).\n- avg_obj_size_bytes: estimated average object size in bytes (optional).\n- max_workers: maximum number of parallel workers (optional).\n- max_batch_size: maximum number of objects per batch. (default: 1_000_000)\n- decrypt: decrypt data using Fernet. (ignores the only_fields parameter)\n\nRefer to `search_queryset` for full parameter details.\n\n## Default Settings\n\n`django-eose` defines default settings in `django_eose/settings.py`:\n\n- MEMORY_FRACTION\n- IMAP_CHUNKSIZE\n- EXECUTOR\n- CACHE_TIMEOUT\n- AVG_OBJ_SIZE_FALLBACK\n- MIN_BATCH_SIZE\n- MAX_BATCH_SIZE\n\n## License\n\nMIT \u00a9 2025 Paulo Ot\u00e1vio Castoldi\n\n## Links\n\n[Source](https://github.com/paulootaviodev/django-eose)\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "Django Encrypted Object Search Engine.",
    "version": "0.3.2",
    "project_urls": {
        "Homepage": "https://github.com/paulootaviodev/django-eose"
    },
    "split_keywords": [
        "django",
        " search",
        " multiprocessing",
        " decrypted",
        " cache"
    ],
    "urls": [
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "90568295648f8726d34ef418f7d03edafa1ad1623091ef6f9d57c0e2d8da0fba",
                "md5": "c601a431ec4fc752dc6342966c2174c1",
                "sha256": "5b1e750ecceceb5fc7e3079081831ef7db629ba232b3f5e8281169db526ecd5b"
            },
            "downloads": -1,
            "filename": "django_eose-0.3.2-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "c601a431ec4fc752dc6342966c2174c1",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.10",
            "size": 10473,
            "upload_time": "2025-09-13T22:21:58",
            "upload_time_iso_8601": "2025-09-13T22:21:58.093440Z",
            "url": "https://files.pythonhosted.org/packages/90/56/8295648f8726d34ef418f7d03edafa1ad1623091ef6f9d57c0e2d8da0fba/django_eose-0.3.2-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": null,
            "digests": {
                "blake2b_256": "dfd97d88d04ce018655c5dfa3708206c4eba6cc8ab2880095db3e51039f27eca",
                "md5": "c842a3b371944136a0f38e24dc5913b9",
                "sha256": "9a287458a0031f33fb5fa85c6b11a5e7e5d1626509455e92871c37f2ef976e2c"
            },
            "downloads": -1,
            "filename": "django_eose-0.3.2.tar.gz",
            "has_sig": false,
            "md5_digest": "c842a3b371944136a0f38e24dc5913b9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.10",
            "size": 10396,
            "upload_time": "2025-09-13T22:21:59",
            "upload_time_iso_8601": "2025-09-13T22:21:59.516118Z",
            "url": "https://files.pythonhosted.org/packages/df/d9/7d88d04ce018655c5dfa3708206c4eba6cc8ab2880095db3e51039f27eca/django_eose-0.3.2.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2025-09-13 22:21:59",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "paulootaviodev",
    "github_project": "django-eose",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "requirements": [
        {
            "name": "asgiref",
            "specs": [
                [
                    "==",
                    "3.9.1"
                ]
            ]
        },
        {
            "name": "cffi",
            "specs": [
                [
                    "==",
                    "2.0.0"
                ]
            ]
        },
        {
            "name": "cryptography",
            "specs": [
                [
                    "==",
                    "45.0.7"
                ]
            ]
        },
        {
            "name": "Django",
            "specs": [
                [
                    "==",
                    "5.2.6"
                ]
            ]
        },
        {
            "name": "psutil",
            "specs": [
                [
                    "==",
                    "7.0.0"
                ]
            ]
        },
        {
            "name": "pycparser",
            "specs": [
                [
                    "==",
                    "2.23"
                ]
            ]
        },
        {
            "name": "python-dotenv",
            "specs": [
                [
                    "==",
                    "1.1.1"
                ]
            ]
        },
        {
            "name": "setuptools",
            "specs": [
                [
                    "==",
                    "80.9.0"
                ]
            ]
        },
        {
            "name": "sqlparse",
            "specs": [
                [
                    "==",
                    "0.5.3"
                ]
            ]
        },
        {
            "name": "wheel",
            "specs": [
                [
                    "==",
                    "0.45.1"
                ]
            ]
        }
    ],
    "lcname": "django-eose"
}
        
Elapsed time: 1.60829s