Skip to content

Latest commit

 

History

History
298 lines (226 loc) · 9.12 KB

File metadata and controls

298 lines (226 loc) · 9.12 KB

Logo

Oxyde Admin Auto-generated admin panel for Oxyde ORM with zero boilerplate.

PyPI Downloads


Features

  • Automatic CRUD - list, create, edit, delete from your Oxyde models
  • Search & filters - text search across fields, column filters (FK, bool, string)
  • Foreign key handling - select dropdowns with inline create dialog
  • Many-to-many relations - multi-select widget with junction-table sync
  • Enum & array fields - Enum columns rendered as dropdowns, list[T] as array editors
  • Streaming export - CSV / JSON export of large tables in chunks, with row caps
  • Bulk operations - bulk delete and update from the list view
  • Authentication - pluggable sync/async callback, JWT-ready
  • Theming - 3 presets, 17 colors, 8 surface palettes
  • Multi-framework - FastAPI, Litestar, Sanic, Quart and Falcon adapters

oxyde-admin list view

Requirements

  • Python ≥ 3.10
  • oxyde ≥ 0.5.0
  • One of the supported frameworks (fastapi / litestar / sanic / quart / falcon)
  • An ASGI server (e.g. uvicorn, hypercorn)

Installation

pip install oxyde-admin

Quick start

from fastapi import FastAPI
from oxyde import db
from oxyde_admin import FastAPIAdmin

from models import User, Post, Comment

admin = FastAPIAdmin(title="My Admin")
admin.register(User, list_display=["name", "email"], search_fields=["name", "email"])
admin.register(Post, list_display=["title", "is_published"], list_filter=["is_published"])
admin.register(Comment)

app = FastAPI(lifespan=db.lifespan(default="sqlite:///app.db"))
app.mount("/admin", admin.app)

Open http://localhost:8000/admin/ and get a full CRUD interface for your models. The admin ships its own SPA frontend, so no separate frontend build is required — the static assets are served by the same mount.

edit form

Configuration

All adapters accept the same constructor parameters:

Parameter Default Description
title "Oxyde Admin" Title shown in the UI
prefix "/admin" URL prefix (FastAPI / Sanic / Quart / Falcon; on Litestar set the path via mount)
preset Preset.AURA PrimeVue preset
primary_color PrimaryColor.SKY Accent color
surface Surface.SLATE Surface palette
per_page 100 Maximum page size for the list view
export_chunk_size 10_000 Rows per chunk while streaming an export
max_export_rows 100_000 Hard cap on total exported rows
auth_check None Callable (request) -> bool, sync or async
login_url None Where the UI redirects on 401

Frameworks

FastAPI

from oxyde_admin import FastAPIAdmin

admin = FastAPIAdmin(title="My Admin")
# register models...
app.mount("/admin", admin.app)

Litestar

from litestar import Litestar, asgi
from oxyde_admin import LitestarAdmin

admin = LitestarAdmin(title="My Admin")
# register models...

app = Litestar(
    route_handlers=[
        asgi(path="/admin", is_mount=True)(admin.app),
    ],
)

Sanic

from sanic import Sanic
from oxyde_admin import SanicAdmin

admin = SanicAdmin(title="My Admin", prefix="/admin")
# register models...

app = Sanic("MyApp")
admin.register_exception_handlers(app)
app.blueprint(admin.blueprint)

Quart

from quart import Quart
from oxyde_admin import QuartAdmin

admin = QuartAdmin(title="My Admin", prefix="/admin")
# register models...

app = Quart(__name__)
admin.init_app(app)

Falcon

import falcon.asgi
from oxyde_admin import FalconAdmin

admin = FalconAdmin(title="My Admin", prefix="/admin")
# register models...

app = falcon.asgi.App()
admin.init_app(app)

Model registration

admin.register(
    Post,
    list_display=["title", "author_id", "is_published", "views"],
    search_fields=["title", "content"],
    list_filter=["author_id", "is_published"],
    readonly_fields=["views"],
    ordering=["-views"],
    display_field="title",
    column_labels={"author_id": "Author", "is_published": "Published"},
    exportable=True,
    group="Content",
    icon="pi pi-file-edit",
)
Parameter Description
list_display Columns shown in the list view
search_fields Fields included in text search
list_filter Columns available as filters
readonly_fields Fields disabled in the edit form
ordering Default sort order (prefix - for descending)
display_field Field used as label in FK dropdowns
column_labels Custom column headers
exportable Enable CSV/JSON export (default: True)
group Sidebar group name
icon Sidebar icon (PrimeIcons)

You can also auto-register all models at once:

admin.register_all()

# or exclude specific models
admin.register_all(exclude={InternalModel})

Field types

The admin reads field metadata from _db_meta and renders an appropriate widget:

Type Widget
str / int / float Text / number input
bool Toggle
date / datetime Date / datetime picker
UUID Text input
Enum Dropdown with the enum members
list[T] Array editor (chips for primitive item types)
Foreign key Searchable dropdown with inline create dialog
Many-to-many Multi-select; junction rows synced on save

Tip: Foreign-key and M2M target models must also be registered. Use display_field on the target model to control the label shown in dropdowns; otherwise the first string field (or the primary key) is used.

Theming

from oxyde_admin import Preset, PrimaryColor, Surface

admin = FastAPIAdmin(
    title="My Admin",
    preset=Preset.AURA,
    primary_color=PrimaryColor.TEAL,
    surface=Surface.ZINC,
)

themes

Presets: AURA, LARA, NORA

Colors: NOIR EMERALD GREEN LIME ORANGE AMBER YELLOW TEAL CYAN SKY BLUE INDIGO VIOLET PURPLE FUCHSIA PINK ROSE

Surfaces: SLATE GRAY ZINC NEUTRAL STONE SOHO VIVA OCEAN

Authentication

Note: This section describes the current behavior. The authentication flow will be reworked in the future.

Pass an auth_check callback and a login_url:

async def check_admin(request) -> bool:
    token = request.headers.get("Authorization", "").removeprefix("Bearer ")
    return await verify_admin_token(token)

admin = FastAPIAdmin(
    auth_check=check_admin,
    login_url="/auth/login",
)
  • auth_check may be sync or async — the adapter detects this at runtime.
  • GET <prefix>/api/config is intentionally not gated by auth_check so the unauthenticated UI can read login_url and the theme on the login screen.
  • The frontend stores the token in localStorage under the key admin_token and sends it as Authorization: Bearer <token> on every API request. On a 401 it clears the token and redirects to login_url.

Your login_url endpoint must accept POST {"email": "...", "password": "..."} and return {"token": "<...>"} on success, or a non-2xx response with {"detail": "..."} on failure.

API

The admin UI talks to the backend through the following endpoints (relative to the admin prefix):

GET    /api/config
GET    /api/models
GET    /api/models/counts
GET    /api/<model>/schema
GET    /api/<model>?page=&per_page=&ordering=&search=&<filter>=
POST   /api/<model>
GET    /api/<model>/<pk>
PATCH  /api/<model>/<pk>
DELETE /api/<model>/<pk>
GET    /api/<model>/options?search=&limit=&include=
GET    /api/<model>/export?format=csv|json&ids=&ordering=&search=
POST   /api/<model>/bulk-delete   { "ids": [...] }
POST   /api/<model>/bulk-update   { "ids": [...], "data": {...} }

<model> is the table name (e.g. users, not User). Schema responses include x-db-* extensions (primary key, FK target, nullable, default, db type, max length, enum members, array item type, M2M target / through) that you can use to drive a custom UI — see oxyde_admin/schema.py for the full list.

Examples

Working applications with auth, fixtures, FK / M2M relations, and enum / array fields are in examples/ for each supported framework (FastAPI, Litestar, Sanic, Quart, Falcon).

License

This project is licensed under the terms of the MIT license.