Skip to content

Admin Interface

A web-based dashboard that lets you view, create, edit, and delete your data without writing code.


What is an Admin Interface?

An admin interface (or admin panel) is a private website where you manage your application's data. Instead of writing database queries or building forms manually, Aksara generates a complete management interface automatically from your models.

from aksara.contrib.admin import site, ModelAdmin, include_admin
from myapp.models import Post

# Register a model with the admin site
@site.register(Post)
class PostAdmin(ModelAdmin):
    list_display = ["title", "author", "is_published", "created_at"]
    search_fields = ["title", "content"]
    list_filter = ["is_published"]

# Mount the admin onto your app at /admin/
include_admin(app)

Quick Start

1. Register Models

There is a ready-to-use global admin site, site. Registering a model tells the admin: "I want to manage this type of data." Once registered, the admin creates pages to list, add, edit, and delete records.

# admin.py
from aksara.contrib.admin import site, ModelAdmin
from myapp.models import Post, Author, Category

# Full control: customize how Post appears in admin
@site.register(Post)
class PostAdmin(ModelAdmin):
    list_display = ["title", "author", "is_published"]

# Quick registration: use all defaults
site.register(Category)

2. Mount the Admin

include_admin() attaches Admin routes, session and rate-limit middleware, and static files. The Admin form handlers enforce CSRF checks.

# main.py
from aksara import Aksara
from aksara.contrib.admin import include_admin
import myapp.admin  # noqa: F401 — registers models with `site`

app = Aksara(database_url="postgresql://localhost/myapp", enable_admin=False)
include_admin(app)              # Admin at /admin/
# include_admin(app, prefix="/manage")   # …or a custom prefix

Auto-mount in development

When debug=True (and the auth contrib is available), Aksara auto-mounts the admin at /admin/. Choose that automatic path or the explicit mounting shown above, which sets enable_admin=False before calling include_admin(). Do not mount the same site/prefix twice. enable_admin=True selects automatic mounting outside debug mode too; it is not needed for explicit mounting.

3. Access the Admin

Start your server and navigate to http://localhost:8000/admin/. You'll see a dashboard listing the apps and models you can manage. Admin access requires an authenticated staff user (is_staff=True).


Key Features

Feature What It Does
Auto-generated UI List, add, edit, and delete pages generated from your models
Search search_fields adds a search box across model fields
Filters list_filter adds a sidebar to narrow records by field value
Ordering & pagination ordering, sortable columns, and list_per_page
Bulk actions Run an operation on selected rows (incl. built-in delete)
Permissions Per-model and per-object access control
Custom columns Computed/formatted columns from ModelAdmin methods
Structured widgets JSON and array editors for complex fields

Core Concepts

Models vs. ModelAdmin

  • A Model defines your data structure (what fields exist, what types they are).
  • A ModelAdmin controls how that model appears in the admin (which columns show, what's searchable, how forms are laid out).
class Post(Model):
    title = fields.String(max_length=200)
    content = fields.Text()
    is_published = fields.Boolean(default=False)

@site.register(Post)
class PostAdmin(ModelAdmin):
    list_display = ["title", "is_published"]   # columns in the list
    search_fields = ["title", "content"]        # fields to search

List View vs. Detail View

  • List View: a paginated table of records, with optional search, filters, sortable columns and bulk actions.
  • Detail View: a form for creating or editing a single record, optionally grouped into fieldsets.

Admin vs. Studio

Aksara ships two browser UIs with different jobs:

UI Path Use it for
Admin /admin/ Day-to-day data management by authenticated staff users: create records, edit content, run bulk actions, and review model data.
Studio (experimental) /studio/ui Developer/operator inspection: models, routes, migrations, diagnostics, AI tools, and project health.

Use Admin when a user is managing application data. Use Studio when a developer or operator is inspecting how the application is built and running. They share the same app process, but their security settings are separate.


Security Defaults

Admin access requires a staff user by default. Form POSTs use a same-site CSRF cookie and hidden form token. Admin POST requests are rate-limited with process-local counters per client address and request path; this is best-effort abuse resistance, not a shared fleet quota. See the throttling guide for the precise boundary.

Do not disable CSRF in production

AKSARA_ADMIN_CSRF_ENABLED=false is intended only for controlled tests or local debugging. Leave CSRF enabled for deployed admin sites.


Registration example

This configuration assumes myapp.models already defines the Post, Author, Category and Tag fields referenced below, the database is configured, and their migrations have been applied. It is not a standalone application. For initial model/migration setup, use the first-project guide; for account creation and password verification, see authentication.

# admin.py
from aksara.contrib.admin import site, ModelAdmin, action
from myapp.models import Post, Author, Category, Tag


@site.register(Post)
class PostAdmin(ModelAdmin):
    """Manage blog posts."""

    list_display = ["title", "author", "category", "is_published", "created_at"]
    list_display_links = ["title"]
    list_filter = ["is_published", "category"]
    search_fields = ["title", "content"]
    ordering = ["-created_at"]
    list_per_page = 25

    fieldsets = [
        (None, {"fields": ["title", "slug", "content"]}),
        ("Publication", {
            "fields": ["author", "category", "tags", "is_published"],
            "classes": ["collapse"],
        }),
    ]
    readonly_fields = ["created_at", "updated_at"]
    prepopulated_fields = {"slug": ("title",)}
    actions = ["publish_selected"]

    @action(description="Publish selected posts", permissions=["change"])
    async def publish_selected(self, request, queryset):
        count = await queryset.update(is_published=True)
        self.message_user(request, f"Published {count} posts.")


site.register(Author)
site.register(Category)
site.register(Tag)
# main.py
from aksara import Aksara
from aksara.contrib.admin import include_admin
import myapp.admin  # noqa: F401

app = Aksara(database_url="postgresql://localhost/myapp", enable_admin=False)
include_admin(app)

  • AdminSite — Configure and mount admin sites
  • ModelAdmin — Customize how each model appears
  • Permissions — Control who can access what
  • Actions — Define and guard bulk operations
  • Widgets — Configure JSON and array form widgets
  • Models — Define your data structure