Hooks¶
Hooks are your functions, called around every SQL statement on djox's
ENGINE: Django's sync ORM and every djox.QuerySet method, the fast lane
included, from sync or async code.
import logging
import djox
logger = logging.getLogger(__name__)
def tag_with_service(query: djox.Query) -> djox.Query:
return query.with_sql(f"/* service: shop */ {query.sql}")
def warn_if_slow(query: djox.Query, finished: djox.QueryFinished) -> None:
if finished.seconds > 0.1:
logger.warning("slow query (%.3fs): %s", finished.seconds, query.sql)
djox.add_hooks(djox.Hooks(before_query=tag_with_service, after_query=warn_if_slow))
Use them to watch statements (time, log, count them per request) or change them (add a tracing comment, block writes to a read-only replica).
| Hook | When | Returns |
|---|---|---|
before_query(query) |
before each statement | None to change nothing, or a new djox.Query to run instead |
after_query(query, finished) |
after each statement, also when it failed (finished.error) |
None |
djox.Query¶
alias,sql(with%splaceholders),parameters, andmany(forexecutemany()).query.with_sql(...)andquery.with_parameters(...)make a changed copy.
Rules¶
- In order: hooks run in the order they were added; each
before_querysees what the previous one returned. - Raising in
before_querystops the statement; the caller gets the error. - Any object works:
djox.add_hooks()takesdjox.Hooks(...)or any object withbefore_queryand/orafter_querymethods.djox.remove_hooks()takes it away again. - Plain functions, not
async def: hooks also run inside sync queries, where nothing can be awaited. - A streamed
aiterator()is one statement: the hooks see it once, when its first chunk arrives.
Not hooked¶
- Django's signals (
pre_save,post_delete...) keep working as always: use them for model events. djox.connections[alias](Raw SQL), the layer below the ORM, has no hooks.