Skip to main content

django typesense

Build codecov Code style: black PyPI download month PyPI version Python versions Django Versions PyPI License

What is it?

Faster Django Admin powered by Typesense

Quick Start Guide

Installation

pip install django-typesense

or install directly from github to test the most recent version

pip install git+https://github.com/Siege-Software/django-typesense.git

Configuration

Update your settings to include the following

  • Add django_typesense to the list of installed apps.
...
INSTALLED_APPS = [
    ...
    "django_typesense"
]
  • Add TYPESENSE connection details
...
TYPESENSE = {
    "api_key": "xyz",
    "nodes": [{"host": "0.0.0.0", "port": "8108", "protocol": "http"}],
    "connection_timeout_seconds": 2
}

Follow this guide to install and run typesense

Create Collections

Throughout this guide, we’ll refer to the following models, which comprise a song catalogue application:

from django.db import models


class Genre(models.Model):
    name = models.CharField(max_length=100)

    def __str__(self):
        return self.name


class Artist(models.Model):
    name = models.CharField(max_length=200)

    def __str__(self):
        return self.name


class Song(models.Model):
    title = models.CharField(max_length=100)
    genre = models.ForeignKey(Genre, on_delete=models.CASCADE)
    release_date = models.DateField(blank=True, null=True)
    artists = models.ManyToManyField(Artist)
    number_of_comments = models.IntegerField(default=0)
    number_of_views = models.IntegerField(default=0)
    duration = models.DurationField()
    description = models.TextField()

    def __str__(self):
        return self.title
     
    @property
    def release_date_timestamp(self):
        # read https://typesense.org/docs/0.25.0/api/collections.html#indexing-dates
        return self.release_date.timestamp() if self.release_date else self.release_date
      
    def artist_names(self):
        return list(self.artists.all().values_list('name', flat=True))
        

For such an application, you might be interested in improving the search and load times on the song records list view.

from django_typesense.collections import TypesenseCollection
from django_typesense import fields


class SongCollection(TypesenseCollection):
    # At least one of the indexed fields has to be provided as one of the `query_by_fields`. Must be a CharField
    query_by_fields = 'title,artist_names,genre_name'
    
    title = fields.TypesenseCharField()
    genre_name = fields.TypesenseCharField(value='genre.name')
    genre_id = fields.TypesenseSmallIntegerField()
    release_date = fields.TypesenseDateField(value='release_date_timestamp', optional=True)
    artist_names = fields.TypesenseArrayField(base_field=fields.TypesenseCharField(), value='artist_names')
    number_of_comments = fields.SmallIntegerField(index=False, optional=True)
    number_of_views = fields.SmallIntegerField(index=False, optional=True)
    duration = fields.DurationField()

It's okay to store fields that you don't intend to search but to display on the admin. Such fields should be marked as un-indexed e.g:

number_of_views = fields.SmallIntegerField(index=False, optional=True)

Update the song model as follows:

from django_typesense.mixins import TypesenseModelMixin

class Song(TypesenseModelMixin):
    ...
    collection_class = SongCollection
    ...

The TypesenseModelMixin provides a Manager that overrides the update and delete methods of the Queryset. If your model has a custom manager, make sure the custom manager inherits django_typesense.mixin.TypesenseManager

How the value of a field is retrieved from a model instance:

  1. The collection field name is called as a property of the model instance
  2. If value is provided, it will be called as a property or method of the model instance

Where the collections live is totally dependent on you but we recommend having a collections.py file in the django app where the model you are creating a collection for is.

Instead of this in the admin:

@admin.display('Genre')
def genre_name(self, obj):
    return obj.genre.name

Do this:

@admin.display('Genre')
def genre_name(self, obj):
    # genre_name is field in the Collection. You can also store the object url as html
    return obj.genre_name

Search Collections

Using Typesense for search

from django_typesense.utils import typesense_search

from .models import Song


def search_songs(request):
    search_term = request.GET.get("q", None)
    songs = Song.objects.all()

    if search_term:
        data = {
            "q": search_term,
            "query_by": Song.collection_class.query_by_fields,
            # Include other search parameters here
            # https://typesense.org/docs/27.1/api/search.html#search-parameters
        }
        res = typesense_search(Song.collection_class.schema_name, **data)
        ids = [result["document"]["id"] for result in res["hits"]]
        songs = songs.filter(id__in=ids)

    ...

Update Collection Schema

To add or remove fields to a collection's schema in place, update your collection then run: python manage.py updatecollections. Consider adding this to your CI/CD pipeline.

This also updates the synonyms

How updates are made to Typesense

  1. Signals - django-typesense listens to signal events (post_save, pre_delete, m2m_changed) to update typesense records. If update_fields were provided in the save method, only these fields will be updated in typesense.

  2. Update query - django-typesense overrides Django's QuerySet.update to make updates to typesense on the specified fields

  3. Manual - You can also update typesense records manually e.g after doing a bulk_create

objs = Song.objects.bulk_create(
    [
      Song(title="Watch What I Do"),
      Song(title="Midnight City"),
   ]
)
collection = SongCollection(objs, many=True)
collection.update()

Admin Integration

To make a model admin display and search from the model's Typesense collection, the admin class should inherit TypesenseSearchAdminMixin. This also adds Live Search to your admin changelist view.

from django_typesense.admin import TypesenseSearchAdminMixin

@admin.register(Song)
class SongAdmin(TypesenseSearchAdminMixin):
    ...
    list_display = ['title', 'genre_name', 'release_date', 'number_of_views', 'duration']
    
    @admin.display(description='Genre')
    def genre_name(self, obj):
        return obj.genre.name
    ...

Indexing

For the initial setup, you will need to index in bulk. Bulk updating is multi-threaded. Depending on your system specs, you should set the batch_size keyword argument.

from django_typesense.utils import bulk_delete_typsense_records, bulk_update_typsense_records

model_qs = Song.objects.all().order_by('id')  # querysets should be ordered
bulk_update_typesense_records(model_qs, batch_size=1024)

Custom Admin Filters

To make use of custom admin filters, define a filter_by property in the filter definition. Define boolean typesense field has_views that gets it's value from a model property. This is example is not necessarily practical but for demo purposes.

# models.py
class Song(models.Model):
    ...
    @property
    def has_views(self):
        return self.number_of_views > 0
    ...

# collections.py
class SongCollection(TypesenseCollection):
    ...
    has_views = fields.TypesenseBooleanField()
    ...
class HasViewsFilter(admin.SimpleListFilter):
    title = _('Has Views')
    parameter_name = 'has_views'

    def lookups(self, request, model_admin):
        return (
            ('all', 'All'),
            ('True', 'Yes'),
            ('False', 'No')
        )

    def queryset(self, request, queryset):
        # This is used by the default django admin
        if self.value() == 'True':
            return queryset.filter(number_of_views__gt=0)
        elif self.value() == 'False':
            return queryset.filter(number_of_views=0)
            
        return queryset

    @property
    def filter_by(self):
        # This is used by typesense
        if self.value() == 'True':
            return {"has_views": "=true"}
        elif self.value() == 'False':
            return {"has_views": "!=false"}

        return {}

Note that simple lookups like the one above are done by default (hence no need to define filter_by) if the parameter_name is a field in the collection

Synonyms

The synonyms feature allows you to define search terms that should be considered equivalent. Synonyms should be defined with classes that inherit from Synonym

from django_typesense.collections import Synonym

# say you need users searching the genre hip-hop to get results if they use the search term rap

class HipHopSynonym(Synonym):
    name = 'hip-hop-synonyms'
    synonyms = ['hip-hop', 'rap']
 
# Update the collection to include the synonym
class SongCollection(TypesenseCollection):
    ...
    synonyms = [HipHopSynonym]
    ...
    

To update the collection with any changes made to synonyms run python manage.py updatecollections

Metadata

Release files for django-typesense 0.1.4

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for django-typesense 0.1.4
File Size Uploaded Provenance
django_typesense-0.1.4.tar.gz 30.3 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for django-typesense 0.1.4
File Interpreter ABI Platform
django_typesense-0.1.4-py2.py3-none-any.whl Python 3, Python 2 none any Details

Total release size: 64.8 kB

Release files / django_typesense-0.1.4.tar.gz

Download URL django_typesense-0.1.4.tar.gz
Size 30.3 kB
Tags Source
SHA-256 checksum
How to use checksums
d51db84b101ce4783acb2d086a98e5053a9e96ae7fa17b477cf65b5efc2f6c71
BLAKE2b-256 checksum
How to use checksums
bfbd349edcd55f48d5f6cf984798a3a9d05881d1e1269348153610ed6e3e797d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 23, 2026.

Transparency log

Release files / django_typesense-0.1.4-py2.py3-none-any.whl

Download URL django_typesense-0.1.4-py2.py3-none-any.whl
Size 34.4 kB
Tags Python 2 Python 3
SHA-256 checksum
How to use checksums
95e3dea4006e1f9caa73227025b761a823abbb6a2ad12a7e5d5287489594a84c
BLAKE2b-256 checksum
How to use checksums
aa5403f8c36ed6e4dc871bac18c04cf58c3ad736dad07c52f80660396924247c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/6.1.0 CPython/3.13.12

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 23, 2026.

Transparency log

Security for django-typesense 0.1.4

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_typesense-0.1.4.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Apr 23, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page