django-ask-ai
Let people ask your Django app questions in plain language — without giving AI a database cursor, your source code, or the power to change anything.
Staff, support, and product people already live in Django admin and your product UI. They want answers like “how many open invoices this month?” or “what do the status values mean?” Engineers want that too — but not by wiring ChatGPT to SQL, pasting the schema into a vendor chat, or letting an agent “just run tools” against production.
django-ask-ai is the drop-in middle path:
The LLM only translates. Django validates, scopes, executes read-only, logs, and caches. Your Groups decide who sees what.
Invoice.objects.ask("how many open invoices this month?", user=request.user)
# → Group scope → allowlisted ORM → aggregate → plain-language answer
$ python manage.py ask_ai "what do the status values mean on Invoice?"
$ python manage.py ask_ai --doctor
Who is this for?
| Person | What they get |
|---|---|
| End users / staff | Talk to their data in ordinary language — from admin, CLI, API, widget, or Python |
| Engineers | One package, not a custom agent stack. Plug in Ollama / OpenAI / OpenRouter / Anthropic / Gemini / … |
| Security / compliance | No SQL generation. No writes. Model never sees a cursor or your source tree. Every ask is in AskLog |
Real use case: a support lead opens Invoice admin, types “how many overdue?”, gets a number under their Group’s visible models and excluded fields. A manager with aggregates_only never gets raw customer rows. “Delete all unpaid orders” is refused and logged. The same question works from manage.py ask_ai or a DRF client when a product UI needs “talk to your data” over HTTP.
Why this exists (and why not “just an AI agent”?)
| Concern with AI agents / text-to-SQL | What django-ask-ai does |
|---|---|
| “What if the model invents SQL?” | It never runs SQL. It proposes ORM JSON; an AST allowlist decides |
| “What if it runs destructive actions?” | Writes are not allowlisted — delete() / update() / create() / raw() blocked in the validator (string + AST), not by asking the model nicely |
| “What if my codebase / settings leak into the prompt?” | The model sees schema + vocabulary you choose — not your repo, secrets, or connection strings |
| “What if support sees another tenant’s rows?” | Scopes (Django Groups): schema allowlist, field exclude, row_filter, aggregates_only — enforced in code |
| “Agents are heavy and every ask burns tokens” | Schema, relations, today/yesterday, and host metrics often answer with 0 tokens. Aggregate answers cache |
One sentence: The LLM is a translator. Django is the executor. Your Groups are the permission system.
Out of the box
No custom agent framework. After install + mixin:
| Feature | What you get |
|---|---|
AskAdminMixin |
Ask panel on each ModelAdmin (changelist + change form), suggestion chips from _meta |
manage.py ask_ai |
CLI one-shot + REPL; --doctor for install health |
| DRF API | HTTP “talk to your data” — sessions, /ask/capabilities/ |
| Widget / console | {% ask_widget %} / {% ask_console %} in your pages |
.objects.ask() |
Same pipeline from Python views and services |
| Pluggable LLMs | Ollama (default), OpenAI, OpenRouter (OpenAI-compatible BASE_URL), Anthropic, Gemini, Groq, Mistral, Cohere, Together, Azure, Bedrock |
| Schema / relations / choices | Live _meta — often no LLM call |
| Today / yesterday · status / period | Deterministic paths from your fields & choices |
| Clarify unknown terms | From your visible models |
| Novel data questions | LLM → AST validate → cost gate → execute under scope |
Audit logging (AskLog) |
Every ask — answers and refusals — with scope, expression, tokens, stage |
| Answer cache | Aggregate hits via Django cache (CACHE_ALIAS → Redis/Memcached in prod) |
| API sessions | Multi-turn conversation state in cache (not package DB tables) |
| Charts · follow-ups | Group-by chart payloads + “Why?” drill-down suggestions |
| Certified questions · metrics | Freeze weekly asks → 0-token replay |
| Knowledge providers | Local docs + optional MCP for structure/knowledge asks |
ask_eval / ask_watch |
Regression suites + anomaly watch on metrics |
| Celery schedules | Optional recurring asks + webhooks |
Optional (5 minutes): teach your words in ask_context.py. The engine stays domain-agnostic — shop, library, billing, HR all plug in the same way.
Quickstart
pip install django-ask-ai
INSTALLED_APPS = [..., "django_ask_ai"]
from django_ask_ai import AskMixin
class Invoice(AskMixin, models.Model):
ask_exclude = ["internal_notes"]
ask_business = "An invoice is overdue if due_at < today and status != paid."
# admin.py — plug and play per model
from django.contrib import admin
from django_ask_ai import AskAdminMixin
@admin.register(Invoice)
class InvoiceAdmin(AskAdminMixin, admin.ModelAdmin):
list_display = ("id", "status", "total")
Local (Ollama) or cloud (OpenRouter / OpenAI / …)
# settings.py — Ollama (default, offline)
ASK_AI = {
"BACKENDS": {
"default": {
"PROVIDER": "ollama",
"MODEL": "llama3.1",
"BASE_URL": "http://localhost:11434",
},
},
"SCOPES": {
"support": {
"schema": ["billing.Subscription", "billing.Invoice"],
"exclude": ["customer__email"],
},
"managers": {"schema": ["billing"], "data": "aggregates_only"},
},
# "CACHE_ALIAS": "default", # point at Redis in production
}
# OpenRouter (or any OpenAI-compatible gateway) — same provider, different BASE_URL
ASK_AI = {
"BACKENDS": {
"default": {
"PROVIDER": "openai",
"MODEL": "openai/gpt-4o-mini",
"API_KEY": "…",
"BASE_URL": "https://openrouter.ai/api/v1",
},
},
}
python manage.py migrate
python manage.py ask_ai --doctor
python manage.py ask_ai "how many open invoices?"
{% load ask_ai %}
{% ask_console %} {# or {% ask_widget %} #}
Teach weekly questions (optional, high value)
# myapp/ask_context.py — autodiscovered
ASK_CONTEXT = {
"glossary": {"ARR": "billing.Subscription"},
"rules": ["Trial accounts are excluded from ARR."],
"metrics": {
"arr": {
"description": "Monthly recurring revenue from active subscriptions",
"expression": (
'Subscription.objects.filter(status="active")'
'.aggregate(v=Sum("mrr"))'
),
"aliases": ["ARR", "monthly recurring revenue"],
"model": "billing.Subscription",
},
},
}
How a question is answered
question
│
├─► scope (Django Groups) ──► intent (data|knowledge|decision|structure)
│
├─► aggregate cache hit? ──► return + AskLog
│
├─► library? (metric / certified / temporal / breakdown) ──► 0 tokens
│
├─► structure / definition from host metadata
│
└─► LLM translate → AST validate → cost gate → execute → format
→ cache aggregates → follow_ups + citations + AskLog
- Logging:
AskLogrecords user, scope, surface, question, expression, tokens, duration, block stage — admin changelist included. - Caching: repeated aggregate answers and API session turns live in Django’s cache framework — no package-owned chat tables.
- Safety: 150+ hostile-expression corpus in CI. Full threat model:
docs/security-model.md.
Surfaces (same safe pipeline)
| Surface | Typical use |
|---|---|
AskAdminMixin |
Staff already in admin |
manage.py ask_ai |
Engineers / ops on the command line |
| DRF API | Product UI, mobile, or another service over HTTP |
| Widget / console | Embed chat in your own templates |
.objects.ask() |
Views, jobs, notebooks |
| Celery schedules + webhooks | Optional recurring asks |
Providers (pluggable)
Ollama (default) · OpenAI · OpenRouter (via OpenAI-compatible BASE_URL) · Anthropic · Gemini · Groq · Mistral · Cohere · Together · Azure OpenAI · Bedrock — routing, fallbacks, mock_llm() for CI. Django is the only hard dependency.
Offline demo in under 5 minutes (Ollama + SQLite)
No cloud keys. Stage-safe.
ollama pull llama3.1
cd example_project
pip install -e "..[dev,drf]"
unset ASK_AI_PROVIDER ASK_AI_API_KEY ASK_AI_BASE_URL OPENROUTER_API_KEY
python manage.py migrate && python manage.py seed_demo
python manage.py ask_ai --doctor # backend ollama: ok
python manage.py ask_ai "orders by status"
python manage.py runserver # admin → Order → Ask AI
Full talk script: example_project/OFFLINE_DEMO.md.
Example hosts
example_project/ is a shop dogfood host. A second library/loans host proves the engine is not shop-specific.
Production
Safe by default. Valuable when taught. Freeze weekly asks as metrics or
certified questions; run ask_eval before demos; put CACHE_ALIAS on Redis.
Playbook: docs/production.md.
Docs
| Topic | Path |
|---|---|
| Quickstart | docs/quickstart.md |
| Offline demo | example_project/OFFLINE_DEMO.md |
| Scopes / Group cookbook | docs/scopes.md |
| Compatibility vs others | COMPAT.md |
| Production | docs/production.md |
| Security | docs/security-model.md |
| Market | docs/market.md |
| Vision | docs/vision.md |
| Site | https://mabukhashabeh.github.io/django-ask-ai/ |
License
MIT
Release files for django-ask-ai 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| django_ask_ai-0.1.0.tar.gz | 181.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_ask_ai-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 327.7 kB
Release files / django_ask_ai-0.1.0.tar.gz
| Download URL | django_ask_ai-0.1.0.tar.gz |
|---|---|
| Size | 181.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
b71e19b5011376274c4cd3af04b47f5959963d466bd9ba5d10e2374abbeaf413
|
|
BLAKE2b-256 checksum How to use checksums |
13f2ce0bb1d55e27ec2cecd9b8e6f1643fa05991b0eb4155a9a08cdd3ff9047a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 10, 2026.
Transparency logRelease files / django_ask_ai-0.1.0-py3-none-any.whl
| Download URL | django_ask_ai-0.1.0-py3-none-any.whl |
|---|---|
| Size | 146.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3157001480b68b4903af41f2f86fee55dfec4d45158fa26ed0f59e8f46dea56d
|
|
BLAKE2b-256 checksum How to use checksums |
1f89ffc5fd927dcdf445feaaf312825d89e3fc3f42be4b91c35370a8b1bec3e0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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 Aug 10, 2026.
Transparency log