This release is a pre-release and may not be stable for production use.
🚀 SnapAdmin — Declarative Django Admin & API
Define your model fields once — get a feature-rich Django admin, a REST API with Swagger docs, a
GraphQL API, and optional Elasticsearch search. Every surface can be switched on or off with a
single setting, and expensive ?search= queries are routed to Elasticsearch automatically when a
model is mirrored there — plain listings stay on the database.
📚 Full Documentation — configuration guide, API reference, examples 📦 Django Packages — compare SnapAdmin against other Django admin packages 📝 Changelog · 🔒 Security policy
⚡ The Core Idea — 3 Steps, Full Stack
# 1. Define a model
from snapadmin import fields as snap, models as snap_models
class Product(snap_models.SnapModel):
name = snap.SnapCharField(max_length=200, searchable=True, show_in_list=True)
price = snap.SnapDecimalField(max_digits=10, decimal_places=2, filterable=True)
available = snap.SnapBooleanField(default=True, filterable=True)
# Optional: mirror to Elasticsearch, auto-delete after a year
# es_storage_mode = snap_models.EsStorageMode.DUAL
# data_retention_days = 365
# 2. settings.py — every surface is a toggle
SNAPADMIN_REST_API_ENABLED = True
SNAPADMIN_GRAPHQL_ENABLED = True
SNAPADMIN_SWAGGER_ENABLED = True
# 3. admin.py
from snapadmin.models import SnapModel
SnapModel.register_all_admins()
That's it — you get a full admin with filters, badges and change logging (Unfold-themed with the
[theme] extra, stock Django admin without it), /api/product/ CRUD with Swagger docs, an
allDemoProducts GraphQL field, and typo-tolerant search when Elasticsearch is on.
→ Field types · SnapModel reference · Admin registration
👀 What You'll See
These screens come from the bundled demo, not the package — they illustrate what SnapAdmin generates for your models.
┌────────────────────────────────────────────────────────────┐
│ SnapAdmin 🔍 Search... admin ▾│
├──────────────┬─────────────────────────────────────────────┤
│ DEMO APP │ Products + Add │
│ Categories │ ┌──────────────────────────────────────────┐│
│ Tags │ │ Name Price In Stock Category ││
│ Products │ │ Premium Laptop $249 ● Active Audio ││
│ Customers │ │ Ergonomic Mouse $89 ● Active Access. ││
│ Orders │ │ USB-C Hub $49 ○ Out Electr. ││
│ Audit Logs │ └──────────────────────────────────────────┘│
│ SYSTEM │ Sidebar filters: Price range │ Available │
│ Dashboard │ Category │ │
└──────────────┴─────────────────────────────────────────────┘
Also generated: Swagger UI at /api/docs/, a GraphQL playground at /api/graphql/, and a
system dashboard at /admin/snapadmin/dashboard/ showing per-model row counts, storage modes and
scheduled jobs.
📦 Installation
pip install django-snapadmin
Requires Python ≥ 3.10 and Django ≥ 5.2. The package is beta — the public API is
stabilising but may still change before 0.1.0 stable, so pin an exact version in production.
Add the stack to INSTALLED_APPS. The Unfold theme is optional (pip install django-snapadmin[theme]) — with it you get the themed UI; without it SnapAdmin renders on Django's
built-in admin. If you use Unfold, its apps must precede django.contrib.admin:
INSTALLED_APPS = [
# Optional themed UI — pip install django-snapadmin[theme]. If used, list before admin:
"unfold", "unfold.contrib.filters", "unfold.contrib.forms", "unfold.contrib.inlines",
"django.contrib.admin", "django.contrib.auth", "django.contrib.contenttypes",
"django.contrib.sessions", "django.contrib.messages", "django.contrib.staticfiles",
"rest_framework", "drf_spectacular", "django_filters", "graphene_django", "snapadmin",
# your apps …
]
Installing SnapAdmin pulls in djangorestframework, drf-spectacular, django-filter and
graphene-django automatically — you only list them. django-unfold is not installed by the
base package; add the [theme] extra for the Unfold-themed admin.
Optional extras
The base install is self-contained and carries only permissive licences (MIT/BSD/Apache), so it is safe for commercial and proprietary use. Opt into the rest:
| Extra | Pulls in | For |
|---|---|---|
theme |
django-unfold |
Unfold-themed admin UI (falls back to Django's built-in admin without it) |
elasticsearch |
elasticsearch |
Full-text search, DUAL / ES_ONLY models |
celery |
celery, django-celery-beat, django-celery-results |
Background tasks (export, GDPR purge, digests, backups) |
backup |
paramiko |
SFTP offsite database backups |
extra-settings |
django-extra-settings |
In-admin dynamic key/value Setting model |
wysiwyg |
django-ckeditor-5 |
Rich-text fields — bundles CKEditor 5 (GPL-or-commercial) |
autocomplete-filter |
django-admin-autocomplete-filter |
AutocompleteFilter list filters (LGPL) |
all |
everything above | — |
→ Full installation guide —
compatibility matrix, extras gotchas, and the licensing notes for [wysiwyg] and MySQL drivers.
Integrate into an existing project
Adding SnapAdmin to a project you already have? Run the read-only doctor — it inspects your
project and prints exactly what to paste (the INSTALLED_APPS ordering, the URL include, the
settings block, the install line), editing nothing:
pip install django-snapadmin
snapadmin-init # a per-item present/missing checklist with ready-to-paste snippets
snapadmin-init --api --graphql # also check the REST / GraphQL configuration
Because it only reports and prints snippets, there's no risk of a bad automatic edit — you review each and paste it yourself. → Integration guide
✨ Features
Admin
- Declarative
list_display/search_fields/list_filterstraight from field kwargs - Unfold-themed responsive UI (optional
[theme]extra — falls back to Django's built-in admin), colour-coded status badges, horizontal rows and tabs - Date and numeric range filters; field-level change logging (
old → new) with a history view - Offline mode — per-model IndexedDB prefetch, real backend health checks, sync on reconnect
APIs
- REST CRUD for every
SnapModel, with Swagger + ReDoc, filters derived from field types (range/__in/__isnullplus text lookups tunable per-field, per-model or project-wide withapi_filter_lookups/api_default_text_lookups/SNAPADMIN_API_TEXT_LOOKUPS), and streaming/async export - GraphQL schema generated from the same models, auth-enforced on every traversed relation
- API tokens hashed at rest (SHA-256), shown once, scoped per model — or plug in JWT/session/custom auth
- Privacy controls:
api_exclude_fields,api_write_fields(mass-assignment guard),api_read_only/api_http_method_names(serve a model read-only — writes get 405),api_json_filters, PII masking; swap the whole filter chain withSNAPADMIN_API_FILTER_BACKEND
Elasticsearch
- Per-model
DB_ONLY/DUAL/ES_ONLYstorage modes with auto-derived index mappings - Smart routing —
?search=onDUALmodels runs fuzzy on ES; plain listings stay on SQL es_filter()structured term filters,es_aggregate()facets,es_count()true match totals past the search limit,es_scan()deep scan past the 10k window (source=Falsestreams just the pks of N-million matches,limit=Nbounds the walk) — each with a DB fallback when ES is off, ordb_fallback=Falseto fail loudly instead on a table the DB can't scan- Resumable bulk reindex —
snapadmin_reindexpages by apk__gtcursor with live progress,--resume,--parallel, and--tune; it fetches only the ES-mapped columns, and--limit Nbounds a probe run
Operations
- GDPR retention (
data_retention_days) and an immutable audit trail - Error monitoring — spike alerts + daily grouped email digests
- Health alerts — email when a subsystem probe (DB / Elasticsearch / REST API / GraphQL, each skipped when its feature is off) goes down;
snapadmin_health_alert(cron) or thesnapadmin.send_health_alerttask (Beat), with a cooldown so an outage emails once - 3-2-1 database backups — local, network share, and offsite FTPS/SFTP
- Large-dataset tuning — auto
list_select_related(no admin N+1), estimated counts, per-model paging - Generic ETL —
upsert_from_source()andstale_sync()with amax_fractionwipe guard, a non-raisingon_exceed="skip"mode, and a DB-sidestrategy="last_seen"prune that holds no in-memory key set - Pluggable export sources — register a custom row source with
SNAPADMIN_EXPORT_SOURCES(ES-query-backed, key-list, or a custom document shape) while the runner keeps its resumable chunking, progress, cancel and storage - Structured logging via
structlog; i18n in 10 locales - One-command diagnostics —
snapadmin_inforeports the version, connected services (DB / Elasticsearch / Celery), registered models and health as text or--json, with a--health-checkreadiness probe - Feature-adoption audit —
snapadmin_info --section featuresprints a ✓/✗ checklist of which commerce-important capabilities (backups, retention-based deletion, PII masking, audit, read-only models, rate limiting, SSO, …) are actually on or in use in your project vs. left unused - Licence audit —
snapadmin_license_checkreports the licence and 🟢/🟡/🔴 commercial-usability tier of every installed dependency, so you know your install is proprietary-safe
Management commands: snapadmin_info (diagnostics & health), snapadmin_license_check (licence audit), snapadmin_health_alert (email on unhealthy subsystem), snapadmin_reindex, db_backup, send_error_digest, purge_expired_data.
⏱ Nothing runs on its own. SnapAdmin ships no daemon — the retention purge, digests and backups need a Celery Beat entry or a cron line. See Background tasks & scheduling.
⚙️ Configuration
Every surface is a plain Django setting; disabling one removes its URL routes entirely (404):
SNAPADMIN_REST_API_ENABLED = True # REST CRUD endpoints
SNAPADMIN_GRAPHQL_ENABLED = True # GraphQL endpoint
SNAPADMIN_SWAGGER_ENABLED = True # Swagger UI + ReDoc
SNAPADMIN_ES_QUERY_ROUTING = True # route ?search= on DUAL models to Elasticsearch
SNAPADMIN_GRAPHQL_REQUIRE_AUTH = True # auth + per-model perms on every resolver
SNAPADMIN_URL_PREFIX = "" # relocate the whole API surface
→ Full settings reference — every
SNAPADMIN_* knob with its default, grouped by area.
🧩 Extending
SnapAdmin is meant to be customised, not forked:
- Add field types — subclass
SnapFieldwith your own admin introspection - Extend a
SnapModel— overridesave(), add managers, mix in your own behaviour - Add or override REST endpoints — mount your router before SnapAdmin's
- Swap auth, permissions and the ES client — configuration, no code
- Override admin templates and the dashboard — standard Django template resolution
→ Extending & Overriding guide
🌟 Trying the Demo
Fastest — one command, no clone:
pip install django-snapadmin
snapadmin-demo # downloads the demo, migrates, seeds, and serves at localhost:8000
snapadmin-demo (also python -m snapadmin.quickstart) fetches the demo/ directory from the
matching release tag — cached under ~/.cache/snapadmin-demo/, so re-runs are instant and offline —
then installs, migrates, seeds and serves it. Add --interactive for a wizard (SQLite/PostgreSQL,
admin password, debug), --no-serve to only prepare it, or --skip-install to reuse the current
environment. See the demo command guide.
Or from a clone — the full Docker stack (PostgreSQL, Redis and Elasticsearch). The demo lives
under demo/ with example models (Product, Customer, Order) and a seeded database; it is
not published to PyPI, only the top-level snapadmin/ package is:
git clone https://github.com/drofji/django-snapadmin.git
cd django-snapadmin
cp demo/dist.env demo/.env
docker compose -f demo/docker-compose.yml up --build
Then open http://localhost:8000/admin/ (admin / admin).
→ Demo guide — Traefik overlays with HTTPS, the Elasticsearch profile, manual setup without Docker, and the seed command.
📖 Documentation
| Topic | |
|---|---|
| Getting started | Installation · Integrate an existing project · SnapModel · Field types · Admin registration |
| APIs | REST · GraphQL · Tokens · Integrating auth / JWT / ETL |
| Search | Elasticsearch modes · Query routing · Filters · Facets · Deep scan |
| Operations | Diagnostics (snapadmin_info) · Licence audit · Celery & scheduling · GDPR · Backups · Error monitoring · Performance |
| Reference | All settings · Enterprise config · Extending · Migration guides |
Upgrading from drofji-automatically-django-admin? See the
migration guide.
🔒 Security
API tokens are hashed at rest, rich-text HTML is sanitized before display, GraphQL enforces permissions on every traversed relation, and PII masking is available on both APIs. Report vulnerabilities privately — see SECURITY.md for the policy, the supported-versions row, and the production-hardening checklist.
Third-party dependency licences are inventoried in
THIRD_PARTY_NOTICES.md — or run
python manage.py snapadmin_license_check for the same inventory computed from what you actually
installed, with a commercial-usability verdict.
🤝 Contributing
See CONTRIBUTING.md. The suite must stay green with 100% coverage on snapadmin/:
pytest
📜 License
MIT — see LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_snapadmin-0.1.0b5.tar.gz.
File metadata
- Download URL: django_snapadmin-0.1.0b5.tar.gz
- Upload date:
- Size: 492.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b0dbd73f932a964d1cc385b431169fa2edd241336dc91092e1ecf3caf4616b91
|
|
| MD5 |
247371ae66e0c0f4d87576e7456d5f0c
|
|
| BLAKE2b-256 |
2283ffe5d3c3430db69c9eade47df8df717f679cbe3a0fbc7a98bf1a68c9cb7b
|
Provenance
The following attestation bundles were made for django_snapadmin-0.1.0b5.tar.gz:
Publisher:
publish.yml on drofji/django-snapadmin
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_snapadmin-0.1.0b5.tar.gz -
Subject digest:
b0dbd73f932a964d1cc385b431169fa2edd241336dc91092e1ecf3caf4616b91 - Sigstore transparency entry: 2231428974
- Sigstore integration time:
-
Permalink:
drofji/django-snapadmin@962b36d48b853b8db91ef2e38d72d36bff667225 -
Branch / Tag:
refs/tags/v0.1.0b5 - Owner: https://github.com/drofji
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@962b36d48b853b8db91ef2e38d72d36bff667225 -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_snapadmin-0.1.0b5-py3-none-any.whl.
File metadata
- Download URL: django_snapadmin-0.1.0b5-py3-none-any.whl
- Upload date:
- Size: 538.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4146ed2550ef98a50c3c3d4d99ea3443be5433d10e0d66aec7adc0effc9c9f9c
|
|
| MD5 |
b96dbfcda067143ac7265ac15dd5b87b
|
|
| BLAKE2b-256 |
b7e92a3181e642f1eb94511c285c272b6ca6249dec24820b649c8686b20f2f60
|
Provenance
The following attestation bundles were made for django_snapadmin-0.1.0b5-py3-none-any.whl:
Publisher:
publish.yml on drofji/django-snapadmin
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_snapadmin-0.1.0b5-py3-none-any.whl -
Subject digest:
4146ed2550ef98a50c3c3d4d99ea3443be5433d10e0d66aec7adc0effc9c9f9c - Sigstore transparency entry: 2231429684
- Sigstore integration time:
-
Permalink:
drofji/django-snapadmin@962b36d48b853b8db91ef2e38d72d36bff667225 -
Branch / Tag:
refs/tags/v0.1.0b5 - Owner: https://github.com/drofji
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@962b36d48b853b8db91ef2e38d72d36bff667225 -
Trigger Event:
push
-
Statement type: