Skip to main content

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: AskLog records 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)

Source distribution for django-ask-ai 0.1.0
File Size Uploaded
django_ask_ai-0.1.0.tar.gz 181.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for django-ask-ai 0.1.0
File Interpreter ABI Platform
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 log

Release 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

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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