Changelog¶
All notable changes to djox. The format follows Keep a Changelog. Before 1.0, a minor version may break things; each break comes with a migration note.
[Unreleased]¶
Added¶
djox.asgi: Django's ASGI handler, sendingrequest_startedandrequest_finishedon the event loop when that can't block it, instead of hopping to a thread twice per request (an empty async view: 1.3 ms to 0.16 ms).- Quick SQLite reads: a small async read runs right on the calling thread, stopped after
quick_read_limit(a new option, 1 ms) and sent to a reader then (aget(): 174 µs to 52 µs). - The fast lane takes more:
Q()objects,exclude(), and names through foreign keys and one-to-one fields (author__name), in filters and inorder_by(). - The general fast lane: a
djox.QuerySetnotes any chain of calls as a recipe, and Django writes the SQL once per shape of the chain.annotate(),alias(),F()and Django's other expressions, aggregates (aggregate()andaaggregate()too),update()withF(),distinct(),values()with expressions, and filters through reverse and many-to-many relations take the fast lane (aCount()annotation: 670 µs to 148 µs;aaggregate(): 465 µs to 173 µs;aupdate(pages=F("pages") + 1): 495 µs to 169 µs). - New objects on the fast lane:
create(),acreate()anddjox.Model.asave()of a new object reuse theINSERTDjango wrote for the model's first one (acreate(): 502 µs to 269 µs). - TLS on Postgres: djox's async connections are encrypted and checked like libpq's, with the same
OPTIONS(sslmodefromdisabletoverify-full,sslrootcert,sslcert,sslkey), also as arguments ofdjox.Database.postgres(). Built on rustls: nothing to install.
Changed¶
- From async code, saving an object of a model with sync
pre_saveorpost_savereceivers runs on a djox thread, rather than sending each signal to Django's sync thread. - Fewer lookups per query: the Python around each query is about half what it was.
Fixed¶
acreate()now calls a model's ownsave().- An
INSERT ... RETURNINGsent tofetch_all()goes straight to SQLite's writer thread, not through a reader.
0.1.0 - 2026-11-02¶
The first release.
Added¶
- Django
ENGINEs:djox.backends.sqlite3(one copy of SQLite in the process, WAL mode, Django's SQL functions registered) anddjox.backends.postgresql(Django's backend for sync code, a Rust pool for async code). - Async QuerySets:
aget(),acount(),async for,acreate(),aupdate(),adelete(),aget_or_create()... run on djox's connections, not on Django's worker thread. Anything else falls back to Django's own method. DJOX_MODELS,djox.Manageranddjox.Model: put every model, or the ones you choose, on djox,Userincluded, without changing their code or migrations.- The fast lane: simple queries, sync and async, reuse the SQL Django wrote once per query shape, and Rust
builds the results (instances,
values(),values_list(),select_related()). - Transactions:
djox.atomic()anddjox.on_commit()for async code; SQLite writers take turns in asyncio instead of sleeping and retrying. - Streaming:
aiterator()reads a chunk at a time, on a connection of its own. - Related objects:
select_related()on the fast lane,prefetch_related()anddjox.aprefetch_related_objects()off the event loop. - Hooks:
djox.add_hooks()calls plain functions before and after every statement. - Raw SQL:
djox.Database.sqlite()anddjox.Database.postgres(), anddjox.connections[alias]. djox[postgres]: the extra that installs psycopg 3 for Django's sync code on Postgres (psycopg2 isn't supported). djox's async Postgres connections don't support TLS yet.- Tested on Django 5.2, 6.0 and 6.1, Python 3.11 to 3.14, SQLite and Postgres 15+, with 2,395 of Django's own ORM tests ported (2,390 pass).