Skip to main content

LiteAdmin

PyPI Python License: MIT

Django Admin–style admin panel for Litestar and FastAPI, with Tortoise ORM and SQLAlchemy.

React UI ships in litedmin/static/ — no npm needed for normal use.

Install

pip install litedmin
pip install "litedmin[fastapi,sqlalchemy]"   # FastAPI + SQLAlchemy
pip install "litedmin[litestar,tortoise]"    # Litestar + Tortoise
pip install "litedmin[all]"                  # both ORMs + frameworks + dev tools

Core symbols (AdminConfig, OrmSettings, register, ModelAdmin) import without ORM/framework extras. ORM and web stacks load only when you import their modules (or touch lazy attributes on litedmin).

From source (examples / development)

git clone https://github.com/ggb0yyyyyyy/litedmin.git
cd litedmin
pip install -e ".[litestar,tortoise]"      # examples/tortoise (port 8000)
pip install -e ".[litestar,sqlalchemy]"    # examples/sqlalchemy (port 8011)
pip install -e ".[fastapi,tortoise]"
pip install -e ".[all]"

Repository layout

liteDmin/
  litedmin/                 installable package
    backend/
      core/                 AdminSite, config, OrmSettings, decorators
      admin/                ModelAdmin, changelist, formsets, permissions
      api/                  AdminAPI / endpoints
      auth/                 session, backends, UserAdminMixin, system models
      orm/                  Tortoise / SQLAlchemy backends + repositories
      integration/          Litestar & FastAPI Admin mounts, DI helpers
      dto/ storage/
    static/                 bundled React UI
  frontend/                 React sources (rebuild → litedmin/static/)
  examples/                 Litestar + Tortoise / SQLAlchemy demos
  tests/

Quick start (Litestar + Tortoise)

Superuser is not created on app startup. Create it once via CLI, then run the example:

# optional credentials for CLI
export ADMIN_USERNAME=admin
export ADMIN_PASSWORD=admin

py -3.11 -m litedmin createsuperuser --settings examples.tortoise.settings:orm_settings
py -3.11 -m uvicorn examples.tortoise.app:app --host 0.0.0.0 --port 8000

Open http://localhost:8000/admin

SQLAlchemy example: same flow with examples.sqlalchemy.settings:orm_settings and port 8011. Details: examples/README.md, examples/CREDENTIALS.md.

Minimal wiring

from litestar import Litestar, get

# Shared Starlette Admin ASGI app; Litestar/FastAPI only provide mount helpers.
from litedmin.backend.integration.litestar import Admin
from litedmin.backend.integration import init_tortoise_with_litedmin, close_tortoise
# FastAPI: from litedmin.backend.integration.fastapi import Admin
#      or: from litedmin import Admin
# Then: app.mount(admin.prefix, admin.as_asgi_app())

from examples.tortoise.admin_config import ExampleAdminConfig
from examples.tortoise.settings import AUTO_DISCOVER_MODULES, orm_settings

admin = Admin(
    prefix='/admin',
    config=ExampleAdminConfig(),          # AdminConfig: theme / UI / auth_user_model
    auto_discover_modules=AUTO_DISCOVER_MODULES,
)

async def on_startup():
    await init_tortoise_with_litedmin(orm_settings)  # OrmSettings: ORM + DB
    await admin.ensure_started()  # validate admin + sync permissions (no user seed)

async def on_shutdown():
    await close_tortoise()

@get('/')
async def root() -> dict:
    return {'admin': '/admin'}

app = Litestar(
    route_handlers=[root, admin.as_mount()],
    on_startup=[on_startup],
    on_shutdown=[on_shutdown],
)

File / rich-text media storage

Pass any StorageBackend (save / delete / url) into Admin(storage=...). Rich editor uploads go to POST /admin/media/upload and embed the returned url in HTML.

Examples use LocalFileStorage + /media static route — see examples/README.md. Swap in S3/MinIO by implementing the same protocol in your app.

SQLAlchemy apps also call admin.configure_sqlalchemy(...) after init_sqlalchemy_with_litedmin_async — see examples/sqlalchemy/app.py.

ModelAdmin

  • Prefer TortoiseModelAdmin / SQLAlchemyModelAdmin (repository save/delete).
  • Register with @register / AdminSite.register — admin_site is always injected; do not construct ModelAdmin without a site.
  • Permission / persist hooks are async (has_*, get_permissions, get_list_scope_filters, save_model, delete_model, process_extra_fields). Sync getters (get_list_display, …) stay sync.
  • Users with password field: UserAdminMixin.
  • Long readonly textareas: pass options on the widget itself (SPA preview + “Show full text” dialog):
from litedmin import Textarea

class AnalysisAdmin(SQLAlchemyModelAdmin):
    widgets = {
        'error': Textarea(collapse_chars=280),
    }

Field references (SQLAlchemy)

Settings accept plain names ('title', 'author__username') for any ORM. For SQLAlchemy you can also pass the model's own attributes (and Link(...) for relation paths), so a type checker catches a misspelt field:

from litedmin import Link, action, display, register
from litedmin.backend.orm.sqlalchemy import SQLAlchemyModelAdmin

@register(Post)
class PostAdmin(SQLAlchemyModelAdmin):
    list_display = [Post.id, Post.title, Link(Post.author, User.username), 'title_upper']
    search_fields = [Post.title, Link(Post.author, User.email)]
    ordering = [Post.created_at.desc()]
    list_filter = [Post.published, Post.status]

Tortoise models have no field attributes on the class — keep using strings there ('title', 'author__username'). Computed @display columns are always strings.

Tortoise example

from litedmin import action, register, display
from litedmin.backend.orm.tortoise import TortoiseModelAdmin

@action(description='Publish selected', row=True)
async def make_published(modeladmin, request, objects):
    # ``objects`` is a list of instances (not an ORM queryset)
    ...
    # Optional: return a status string for the SPA toast (e.g. background job accepted)
    # return 'Export queued'

@action(description='Refresh cache', toolbar=True, bulk=False, row=False)
async def refresh_cache(modeladmin, request, objects):
    # Page toolbar button (no selection); same POST /{model}/action with ids=[]
    ...
    return 'Refresh queued'

@register(Post)
class PostAdmin(TortoiseModelAdmin):
    list_display = ['title', 'title_upper']
    actions = [make_published, refresh_cache]  # each entry must use @action

    @display(label='Upper title')
    def title_upper(self, obj):
        return obj.title.upper()

    async def has_export_permission(self, request=None, obj=None):
        return True

List actions require @action (Django @admin.action style). Use row=True for per-row buttons; bulk=False to hide from the bulk dropdown; toolbar=True for page-level tools above the list (always empty selection). Signature is always (modeladmin, request, objects).

Custom pages (@admin_page)

Site-level schema-driven forms (not bound to a model). By default they appear in the global AppBar «Tools» menu (Django Admin–style header tools).

from litedmin import admin_page
from litedmin.backend.integration.fastapi import Admin

@admin_page(
    description='Analyze by keys',
    fields=[
        {
            'name': 'keys',
            'label': 'Issue keys',
            'widget_type': 'textarea',
            'required': True,
        },
    ],
    # header=True (default) → AppBar Tools menu
)
async def analyze_by_keys(admin_site, request, data: dict):
    # data == {'keys': 'PRTO-1, PRTO-2'}
    return 'Queued: 2'  # toast, same as @action

admin = Admin(prefix='/admin', pages=[analyze_by_keys], ...)

SPA route: /pages/{page}. API: GET /pages/{page}/schema, POST /pages/{page} with { "data": { … } }. Header links come from GET /models → pages[]. Requires staff/admin access.

Auth

  • Default: session cookie login (SessionAuthBackend + SessionAuth).
  • SSO (Keycloak gateway handoff): GatewayWebAuthBackend — see examples/tortoise/app_gateway_web.py and examples/README.md.

CLI

litedmin createsuperuser --settings examples.tortoise.settings:orm_settings
# or
python -m litedmin createsuperuser --settings module.path:orm_settings

--username / --password / --email, or ADMIN_USERNAME / ADMIN_PASSWORD / ADMIN_EMAIL.

Config split

Object Role
AdminConfig Theme, UI, sidebar groups, optional auth_user_model
OrmSettings orm_type, database URL, app modules for ORM init

Features

  • @register / AdminSite.register ModelAdmin API
  • SQLAlchemy field attributes / Link(...) in ModelAdmin settings (strings for Tortoise)
  • @display computed list columns
  • @action list actions (bulk dropdown + optional row=True / toolbar=True buttons)
  • @admin_page site-level schema-driven forms (AppBar Tools menu; Admin(..., pages=[...]))
  • CSV/JSON export (has_export_permission)
  • Django-like permissions, groups, LogEntry audit trail
  • list_editable, date_hierarchy, bulk actions, inlines
  • Row-level scope via get_list_scope_filters + object-level has_*
  • Double-submit CSRF cookie for session auth (AdminConfig.csrf_protect)
  • StorageBackend protocol for file uploads

Typing

Package is typed; project mypy config is in pyproject.toml ([tool.mypy]).

pip install -e ".[dev]"
python -m mypy litedmin

Change the React UI

pip install -e ".[all]"
# or: pip install -r requirements-dev.txt
bash scripts/build_frontend.sh
git add litedmin/static/

License

MIT

Metadata

Release files for litedmin 0.5.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for litedmin 0.5.2
File Size Uploaded Provenance Actions
litedmin-0.5.2.tar.gz 2.5 MB Without provenance Details for litedmin-0.5.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for litedmin 0.5.2
File Interpreter ABI Platform Actions
litedmin-0.5.2-py3-none-any.whl Python 3 none any Details for litedmin-0.5.2-py3-none-any.whl

Total release size: 5.1 MB

Release files / litedmin-0.5.2.tar.gz

Download URL litedmin-0.5.2.tar.gz
Size 2.5 MB
Tags Source
SHA-256 checksum
How to use checksums
d357a0a612c4dd3d64d0622230786f9e0a5899e20b5e2180b209ef0b0dd07db9
BLAKE2b-256 checksum
How to use checksums
62c356c12cdfdb61ee9e82dfc2a1e0db6b1a14cf64773e5b6bf093d17b8ffbcd
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Release files / litedmin-0.5.2-py3-none-any.whl

Download URL litedmin-0.5.2-py3-none-any.whl
Size 2.6 MB
Tags Python 3
SHA-256 checksum
How to use checksums
3aa590570e87704baf7df7607904aa54ff8796d476a0888a0edf181b71825f1f
BLAKE2b-256 checksum
How to use checksums
b9bad978ff6ece2281f0489666ef99d5f4048b28726cfe42963a5bb3ab170edc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.14.4

Security for litedmin 0.5.2

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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