Skip to main content

django-ragtime

Chunked, pgvector-backed embeddings for Django — built for the retrieval half of RAG. Text is split into chunks, each chunk is embedded, and the vectors live in a separate EmbeddingChunk table so your models' tables stay untouched.

Requirements

  • PostgreSQL with the pgvector extension

Installation

pip install django-ragtime

Add the app (and contenttypes, which chunks depend on) to your settings and run its migrations. The first migration also enables the pgvector extension, so the database user running migrate needs permission to CREATE EXTENSION (otherwise, enable it manually first).

INSTALLED_APPS = [
    # ...
    "django.contrib.contenttypes",
    "django_ragtime",
]
python manage.py migrate django_ragtime

Usage

Add EmbeddingMixin to any of your existing models:

from django.db import models
from django_ragtime.models import EmbeddingMixin


class Article(EmbeddingMixin, models.Model):
    title = models.CharField(max_length=200)

The mixin adds no database columns, so your models need no new migrations. Embeddings live in EmbeddingChunk rows attached to your instances via a generic foreign key; they are deleted automatically when the parent instance is deleted.

To build (or rebuild) an instance's embeddings, pass update_chunks() a callable that embeds a batch of texts:

def embed_texts(texts: list[str]) -> list[list[float]]:
    """One batched call to your embedding API."""
    response = client.embeddings.create(model="text-embedding-3-small", input=texts)
    return [item.embedding for item in response.data]


article.update_chunks(embed_texts, model_name="text-embedding-3-small")

update_chunks() splits the instance's text into chunks (paragraph-aware, controlled by the chunk_size and chunk_overlap class attributes, in characters), embeds them with your callable, and atomically replaces the instance's existing chunks. article.embedding_chunks returns them.

Models you don't own

You don't have to inherit the mixin. The same storage layer works with any saved instance — User, a model from another package, etc.:

from django.contrib.auth.models import User
from django_ragtime import register, update_chunks_for

# In your AppConfig.ready(), so chunks are deleted with the parent:
register(User, fields=["first_name", "last_name"])

update_chunks_for(user, embed_texts, model_name="text-embedding-3-small")

Pass fields (or text=) whenever you call update_chunks_for if you haven't registered defaults. Auto-introspection skips emails, slugs, URLs, and names like password, but listing fields is the safe choice for third-party models.

update_chunks_for(user, embed_texts, fields=["first_name", "last_name"])
update_chunks_for(user, embed_texts, text=user.get_full_name())

chunks_for(user) and delete_chunks_for(user) are the function equivalents of instance.embedding_chunks and deleting those rows.

Search chunks directly, or get the best chunk per parent object:

from django_ragtime.models import EmbeddingChunk

# All matching chunks, nearest first, annotated with .distance
EmbeddingChunk.objects.search(query_vector)

# Restrict to one or more parent model classes
EmbeddingChunk.objects.search_models(query_vector, Article)
EmbeddingChunk.objects.search_models(query_vector, Article, Note)

# Same idea via chaining
EmbeddingChunk.objects.for_models(Article, Note).search(query_vector)

# At most one (best) chunk per parent object; parent via chunk.parent
for chunk in EmbeddingChunk.objects.for_model(Article).nearest_parents(query_vector, limit=10):
    print(chunk.parent, chunk.distance, chunk.text)

Getting the text to embed

get_embedding_text() returns the text an instance is embedded from. By default it concatenates every free-text field on the model (CharField/TextField), skipping slugs, URLs, emails, file paths, and choice fields. To control which fields are used (and their order), declare embedding_fields — dotted paths across relations and zero-argument methods/properties are supported:

class Note(EmbeddingMixin, models.Model):
    embedding_fields = ["subject", "body", "article.title"]

For full control (templates, related-object chunks, etc.), override the method:

def get_embedding_text(self) -> str:
    return f"{self.title}\n{self.render_summary()}"

Development

python -m venv .venv
source .venv/bin/activate
pip install -e ".[dev]"

The tests need Postgres with pgvector; a ready-made container is included:

docker compose up -d
pytest

The database connection can be overridden with the POSTGRES_DB, POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_HOST, and POSTGRES_PORT environment variables (defaults match docker-compose.yml, port 5434).

License

MIT

Metadata

Release files for django-ragtime 0.1.1

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-ragtime 0.1.1
File Size Uploaded Provenance Actions
django_ragtime-0.1.1.tar.gz 17.1 kB Without provenance Details for django_ragtime-0.1.1.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-ragtime 0.1.1
File Interpreter ABI Platform Actions
django_ragtime-0.1.1-py3-none-any.whl Python 3 none any Details for django_ragtime-0.1.1-py3-none-any.whl

Total release size: 30.5 kB

Release files / django_ragtime-0.1.1.tar.gz

Download URL django_ragtime-0.1.1.tar.gz
Size 17.1 kB
Tags Source
SHA-256 checksum
How to use checksums
be6b344426ffb0455114595eb9704e123272313d68a5a7af48b08f4e3fd898d6
BLAKE2b-256 checksum
How to use checksums
091c111f528574587f943851202a0c75477568f6ecae2b66e47d7ff2fe21d44a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / django_ragtime-0.1.1-py3-none-any.whl

Download URL django_ragtime-0.1.1-py3-none-any.whl
Size 13.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
d189f17d4ebcc1c243a8e1c9656b0c4485d31c0cbec1ce172984806235fc6e46
BLAKE2b-256 checksum
How to use checksums
52e53f8936c512bbe55418885893b1dbf3c75462edf5273ee57a31855fc49acb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Security for django-ragtime 0.1.1

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

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.

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files No provenance

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