Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

🚀 SnapAdmin — Declarative Django Admin & API

Describe a model's fields once. Get a full Django admin, a REST API with Swagger docs, a GraphQL endpoint and optional Elasticsearch search — no boilerplate. Every surface is one setting away from being switched off.

Tests PyPI Downloads Python Django License

📚 Full Documentation · 📦 Django Packages · 📝 Changelog · 🔒 Security policy · 🧭 llms.txt (docs map for AI assistants)


🏁 See it running in 60 seconds

No project, no config, nothing to clone:

pip install django-snapadmin
snapadmin-demo

That downloads a ready-made demo project, migrates it, seeds sample data and serves it on http://localhost:8000. Log in at /admin/ with admin / admin and click around. Delete ~/.cache/snapadmin-demo/ when you're done.


🧠 The idea, in three steps

1. Declare the model. The Snap*Field kwargs describe how the field should behave — in the admin, in the API, in search. They add no database migration; they are stripped before Django sees the field.

# models.py
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)

2. Turn the surfaces you want on.

# settings.py
SNAPADMIN_REST_API_ENABLED = True   # /api/… CRUD
SNAPADMIN_GRAPHQL_ENABLED  = True   # /api/graphql/
SNAPADMIN_SWAGGER_ENABLED  = True   # /api/docs/

3. Register. One line — every SnapModel in the project gets an admin.

# admin.py
from snapadmin.models import SnapModel
SnapModel.register_all_admins()

You now have:

/admin/ list view with a search box on name, sidebar filters for price (range) and available, an add/edit form, and field-level change logging
/api/models/demo/Product/ REST list · retrieve · create · update · delete, with filtering, pagination and token auth
/api/docs/ Swagger UI + ReDoc, generated from the same models
/api/graphql/ a Graphene schema with allDemoProducts, permission-checked per relation
/dashboard/ row counts per model, service health, scheduled jobs
┌────────────────────────────────────────────────────────────┐
│  SnapAdmin                           🔍 Search...    admin ▾│
├──────────────┬─────────────────────────────────────────────┤
│  SHOP        │  Products                         + Add     │
│  Categories  │ ┌──────────────────────────────────────────┐│
│  Products    │ │ Name            Price  In Stock  Category ││
│  Customers   │ │ Premium Laptop  $249   ● Active   Audio   ││
│  Orders      │ │ Ergonomic Mouse $89    ● Active   Access. ││
│  SYSTEM      │ │ USB-C Hub       $49    ○ Out      Electr. ││
│  Dashboard   │ └──────────────────────────────────────────┘│
└──────────────┴─────────────────────────────────────────────┘

Field types · SnapModel reference · Admin registration


🧭 How this differs from Unfold, Jazzmin and Grappelli

Those are themes: they restyle the admin you have written. You still write the ModelAdmin — the list_display, the search_fields, the filters — and they make it look modern.

SnapAdmin generates that admin from your field declarations, and generates the REST API, the GraphQL schema and the search mapping from the same ones. It is not an alternative theme; it sits a layer above, and it uses Unfold as its optional theme ([theme] extra). Keep your theme, keep your hand-written ModelAdmin where you want one — SnapAdmin never replaces an admin class you registered yourself.

Themes (Unfold · Jazzmin · Grappelli) SnapAdmin
Admin look ✅ their whole point Unfold's, when you install [theme]
Who writes the ModelAdmin you generated from the field kwargs
REST API + OpenAPI/Swagger generated from the same fields
GraphQL schema generated from the same fields
Elasticsearch indexing/search generated from the same fields
Ops (audit log, GDPR purge, backups, health) built in, each one setting away

If all you want is a better-looking admin, use a theme — it is less machinery. SnapAdmin earns its place when the same models also have to be an API, a search index and an auditable system of record, and you would rather declare that once than maintain four descriptions of the same fields.


🖥 The four commands

Command Answers What it does
snapadmin-demo "What does this thing actually look like?" Downloads and serves a throwaway demo project. Needs no project of your own
snapadmin-init "How do I add this to my existing project?" A read-only doctor: prints a present/missing checklist and ready-to-paste snippets. It never edits your code
snapadmin-info "Is it configured correctly, and is everything up?" Version, database, Elasticsearch, Celery, models, system checks, plus a ✓/✗ feature-adoption audit
snapadmin-license-check "Can I ship this commercially?" The licence and 🟢/🟡/🔴 tier of every installed dependency, with a verdict

The last two inspect a live project, so run them from inside one. They are manage.py commands with a shell shim, and every spelling works — the shim just finds your manage.py and forwards:

snapadmin-info            # ≡ snapadmin_info  ≡  python manage.py snapadmin_info
snapadmin-license-check   # ≡ snapadmin_license_check
snapadmin-init                                  # what's missing to wire SnapAdmin in
snapadmin-init --api --graphql                  # also check the REST / GraphQL config

snapadmin-info                                  # full diagnostic report
snapadmin-info --section features               # just the ✓/✗ capability checklist
snapadmin-info --health-check                   # probes only; non-zero exit if one fails
snapadmin-info --json                           # the same report for CI / monitoring
snapadmin-info --verbose                        # + the full text of any system-check message

snapadmin-license-check                         # every dependency's licence + tier
snapadmin-license-check --critical-only         # only what blocks commercial use

Other management commands, all opt-in and none of them running on their own: snapadmin_reindex (Elasticsearch), snapadmin_health_alert, snapadmin_db_backup, snapadmin_send_error_digest, snapadmin_purge_expired_data, snapadmin_audit_export.

Nothing runs on a schedule by itself. SnapAdmin ships no daemon — the retention purge, digests and backups need a Celery Beat entry or a cron line. → Background tasks & scheduling


📦 Install

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.

Minimal INSTALLED_APPS — the smallest thing that works

Everything below is installed for you by pip install django-snapadmin; you only have to list it.

INSTALLED_APPS = [
    # ── Django itself ───────────────────────────────────────────────────────
    "django.contrib.admin",          # SnapAdmin generates ModelAdmins into this site
    "django.contrib.auth",           # permissions gate both the admin and the API
    "django.contrib.contenttypes",   # required by auth; the audit trail keys off it
    "django.contrib.sessions",       # admin login
    "django.contrib.messages",       # admin "saved successfully" banners
    "django.contrib.staticfiles",    # serves SnapAdmin's CSS/JS

    # ── The API stack (pulled in as dependencies — just list them) ───────────
    "rest_framework",                # the generated REST endpoints are DRF viewsets
    "drf_spectacular",               # builds the OpenAPI schema behind /api/docs/
    "django_filters",                # backs the auto-generated ?field=… query filters
    "graphene_django",               # the generated GraphQL schema

    # ── SnapAdmin ───────────────────────────────────────────────────────────
    "snapadmin",

    "myapp",                         # …your own apps
]
# urls.py
from django.contrib import admin
from django.urls import include, path

urlpatterns = [
    path("admin/", admin.site.urls),
    path("api/", include("snapadmin.urls")),   # REST + Swagger + GraphQL
]

That's a working install: themed-less admin, REST, Swagger and GraphQL. Turning a surface off with SNAPADMIN_*_ENABLED = False removes its routes (404) but you still list the app.

Full INSTALLED_APPS — everything switched on

Each block below corresponds to one optional extra. Add the block and the extra, or neither.

INSTALLED_APPS = [
    # ── Themed UI — pip install django-snapadmin[theme] ─────────────────────
    # MUST come before django.contrib.admin: Unfold overrides admin templates,
    # and Django resolves templates in INSTALLED_APPS order.
    "unfold",
    "unfold.contrib.filters",        # the sidebar range/dropdown filters SnapAdmin generates
    "unfold.contrib.forms",          # themed form widgets
    "unfold.contrib.inlines",        # themed inline formsets

    # ── Rich text — pip install django-snapadmin[wysiwyg] ───────────────────
    # Only needed for wysiwyg=True / SnapRichTextField. Bundles CKEditor 5,
    # which is GPL-or-commercial — that is why it is not a core dependency.
    "django_ckeditor_5",

    # ── Django itself ───────────────────────────────────────────────────────
    "django.contrib.admin",
    "django.contrib.auth",
    "django.contrib.contenttypes",
    "django.contrib.sessions",
    "django.contrib.messages",
    "django.contrib.staticfiles",

    # ── The API stack (always required) ─────────────────────────────────────
    "rest_framework",
    "drf_spectacular",
    "django_filters",
    "graphene_django",

    # ── SnapAdmin ───────────────────────────────────────────────────────────
    "snapadmin",

    # ── Background tasks — pip install django-snapadmin[celery] ─────────────
    # Needed for the GDPR purge, async exports, error digests and backups.
    "django_celery_beat",            # edit the schedule from the admin
    "django_celery_results",         # store task results in the database

    # ── Admin-editable settings — pip install django-snapadmin[extra-settings]
    # SnapAdmin does not use it; add it if you want a runtime key/value Setting
    # model in the admin (the demo shows the pattern).
    "extra_settings",

    # ── Autocomplete list filters — [autocomplete-filter] (LGPL) ────────────
    # For your own AutocompleteFilter admin filters; SnapAdmin core never imports it.
    "admin_auto_filters",

    "myapp",
]

Elasticsearch needs no app entrypip install django-snapadmin[elasticsearch] and set ELASTICSEARCH_ENABLED = True. Same for [backup] (SFTP offsite backups): a dependency, not an app.

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. Everything with a licence caveat is opt-in:

Extra Pulls in Gives you
theme django-unfold The themed admin UI (stock Django admin without it)
elasticsearch elasticsearch Full-text search, DUAL / ES_ONLY models
celery celery, django-celery-beat, django-celery-results Background tasks: async export, GDPR purge, digests, backups
backup paramiko SFTP offsite database backups
extra-settings django-extra-settings An 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

Run python manage.py snapadmin_license_check after installing to see exactly what you ended up with and whether it is still proprietary-safe.

Full installation guide — compatibility matrix, extras gotchas, and the MySQL driver licence note.

Adding it to a project you already have

pip install django-snapadmin
snapadmin-init

snapadmin-init inspects your project and prints a per-item checklist plus the exact snippets to paste — the INSTALLED_APPS ordering, the URL include, the settings block. It edits nothing, so there is no bad automatic change to undo. → Integration guide


✨ What you get

Admin

  • list_display, search_fields and list_filter derived from the field kwargs — no ModelAdmin to write
  • Themed responsive UI with the [theme] extra, colour-coded status badges, tabs and horizontal field rows
  • Date and numeric range filters, autocomplete foreign keys, inlines
  • Field-level change logging (old → new) with a history view
  • Offline mode — a per-model IndexedDB cache that keeps a list view usable with no connection and syncs on reconnect

APIs

  • REST CRUD per model, with Swagger + ReDoc and filters derived from each field's type — ranges, __in, __isnull, text lookups, JSON paths
  • GraphQL from the same models, with permissions enforced on every traversed relation
  • API tokens hashed at rest, shown once, scoped per model — or plug in JWT / session / your own auth
  • Per-model guards: api_exclude_fields (never leaves the server), api_write_fields (mass-assignment allowlist), api_read_only (writes answer 405), PII masking

Search (optional)

Operations

How fast is it?

There are no published benchmark numbers, so this README will not quote any. What ships instead is the means to measure it on your own hardware and data shape, which is the only figure worth acting on:

python demo/manage.py seed_large              # 100,000 customers and orders, batched bulk_create
python demo/manage.py benchmark_list_view     # admin changelist: query count + wall time

benchmark_list_view runs the changelist queryset with and without SnapAdmin's automatic list_select_related, touching a foreign key on every row, so the N+1 it removes shows up in the query count rather than in prose. What is designed in — rather than measured — is documented under large-dataset tuning: estimated counts in place of COUNT(*) on large tables, paging caps, and streaming exports and es_scan() that hold memory flat regardless of result size.


⚙️ Configuration

Every surface is a plain Django setting; switching one off 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

Misconfiguration shows up at startup as a Django system check (snapadmin.W001W007), not as a mystery at request time — read those first when something behaves unexpectedly.

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 SnapField with your own admin introspection
  • Extend a SnapModel — override save(), 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


🌟 The demo, the long way

snapadmin-demo (above) is the fast path. From a clone you also get the full Docker stack with 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 snapadmin/ 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 · Theming · 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

django_snapadmin-0.1.0b6.tar.gz (529.4 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_snapadmin-0.1.0b6-py3-none-any.whl (571.8 kB view details)

Uploaded Python 3

File details

Details for the file django_snapadmin-0.1.0b6.tar.gz.

File metadata

  • Download URL: django_snapadmin-0.1.0b6.tar.gz
  • Upload date:
  • Size: 529.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for django_snapadmin-0.1.0b6.tar.gz
Algorithm Hash digest
SHA256 d21af10dca18edc93b9b2d50cf62c3c958d45891102ae76b50f6f2346bcb9c7d
MD5 50fe241f6f8f41dbf8b168f1295c2e73
BLAKE2b-256 952154d2bdde2218ce4432193861c9422e5a324b164d2eb7fb51172d217b777c

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_snapadmin-0.1.0b6.tar.gz:

Publisher: publish.yml on drofji/django-snapadmin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file django_snapadmin-0.1.0b6-py3-none-any.whl.

File metadata

File hashes

Hashes for django_snapadmin-0.1.0b6-py3-none-any.whl
Algorithm Hash digest
SHA256 b992301b67beb473684ec09818e5baaf2b4318ee9cde938bb2a2de88a2cb2b5a
MD5 88fa1faf9ac9541659eedc71b9926a0c
BLAKE2b-256 1bc7a7457d8bbd67201a7aad4ade0aa1f2b4e9a7a39faf28feeefe3f43cbf24f

See more details on using hashes here.

Provenance

The following attestation bundles were made for django_snapadmin-0.1.0b6-py3-none-any.whl:

Publisher: publish.yml on drofji/django-snapadmin

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.
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