Skip to main content

xladmin backend

xladmin-backend is the backend package published to PyPI as xladmin.

Important:

  • package name on PyPI: xladmin
  • Python import: from xladmin import ...
  • monorepo: Artasov/xladmin

Public API

  • AdminConfig / ModelConfig / FieldConfig
  • ListFilterConfig
  • BulkActionConfig / ObjectActionConfig
  • ModelsBlock
  • HttpConfig
  • create_router(...)

Compatibility aliases are kept:

  • Admin* config names
  • create_admin_router(...)

Read-only models

Set ModelConfig(..., read_only=True) for records that may only be changed through application domain commands. This is a model-level write restriction, separate from FieldConfig.read_only and from user authentication.

The admin rejects create, PATCH, delete, bulk delete, object actions and bulk actions with HTTP 403 before invoking their write handlers. List/detail and relation reads remain available. Metadata includes read_only, removes writable fields and write actions, and marks fields as read-only even when explicit create/update field lists were configured.

Deleting a writable parent is also rejected if the deletion plan would delete a registered read-only child or clear its foreign key. Delete previews expose those dependencies as protected. Custom handlers registered on other writable models are trusted application code; this setting is not a database-wide authorization mechanism for arbitrary SQL issued by them.

The matching import/export extension rejects both import validation and commit, advertises no import formats, and preserves exports. Consumers must update the backend core and extension together. Frontend consumers should use model metadata to hide write controls; hiding controls alone is not the protection.

Scoped relationship writes

ModelConfig.query_for_list(query, session, user) also defines the available IDs for registered relation targets. Standard create/PATCH validates scalar foreign keys, single relationships and every ID in a relationship collection against this scope, even when an unavailable object is already cached in the session. An unavailable ID produces HTTP 400 without committing the parent edit; duplicate collection IDs are deduplicated in request order. Models without a configured scope retain their ordinary relation selection semantics.

Internal mutation helpers now require the runtime registry and authenticated user as keyword arguments. Upgrade the matching import/export extension together: its validation and commit pass the same context, and imported existing targets must also be visible. Custom setters/handlers remain trusted application code. This is assignment validation, not automatic database routing or row-level security for arbitrary SQL.

Minimal Example

from xladmin import AdminConfig, HttpConfig, ModelConfig, create_router

from src.core.auth.dependencies import get_current_user
from src.core.db.session import get_db_session
from src.modules.identity.models import UserORM


config = AdminConfig(
    models=(
        ModelConfig(model=UserORM),
    ),
)

router = create_router(
    HttpConfig(
        registry=config,
        get_db_session_dependency=get_db_session,
        get_current_user_dependency=get_current_user,
        is_allowed=lambda user: bool(user.is_staff),
    ),
)

ModelConfig(model=UserORM) is enough for a basic admin. The library derives default slug, title, search fields, and ordering from the ORM model.

Features

  • list / detail / create / patch / delete endpoints
  • current-user endpoint for frontend sidebar identity: GET /xladmin/me/
  • logout endpoint for frontend logout buttons: POST /xladmin/logout/
  • bulk actions and object actions
  • relation choices and relation filters
  • single and multi-select relation filters via ListFilterConfig(..., multiple=True, input_kind="relation-multiple")
  • overview metadata and model blocks
  • query_for_list and custom search_query_builder
  • mode-specific form fields with hidden_in_create / hidden_in_update
  • custom create defaults with create_item_factory
  • delete preview for single and bulk delete
  • RU / EN locale metadata for the frontend

Current User And Logout

The frontend Shell can show the current user in the sidebar and call logout from the sidebar action. The backend router exposes two endpoints for this:

  • GET /xladmin/me/
  • POST /xladmin/logout/

/xladmin/me/ uses get_current_user_dependency and returns a small payload:

{
  "id": 1,
  "login": "admin@example.com",
  "email": "admin@example.com",
  "name": "Admin"
}

The login value is resolved from the first available user attribute in this order: username, email, login, name, then id.

By default /xladmin/logout/ only checks that the user can access admin and returns 204. Real applications should pass logout_dependency to HttpConfig to clear cookies, sessions, tokens, or any other auth state. Headers and cookies set by logout_dependency are preserved in the final 204 response.

from fastapi import Response
from xladmin import HttpConfig, create_router


async def logout_admin_user(response: Response) -> None:
    response.delete_cookie("session")


router = create_router(
    HttpConfig(
        registry=admin_config,
        get_db_session_dependency=get_db_session,
        get_current_user_dependency=get_current_user,
        is_allowed=lambda user: bool(user.is_staff),
        logout_dependency=logout_admin_user,
    ),
)

If your auth system needs the current user in the logout handler, add it as a regular FastAPI dependency inside your function.

Multi-Select Relation Filters

If one relation filter is not enough, you can expose a multi-select variant that works as an autocomplete with add/remove chips on the frontend.

from xladmin import ListFilterConfig


ListFilterConfig(
    slug="role_ids",
    label="Roles",
    field_name="roles",
    input_kind="relation-multiple",
    multiple=True,
    relation_model=RoleORM,
    relation_label_field="name",
)

Create And Update Fields

If a field should be visible only in one form mode, use hidden_in_create or hidden_in_update.

from xladmin import FieldConfig, ModelConfig


ModelConfig(
    model=UserORM,
    fields={
        "password": FieldConfig(
            input_kind="password",
            hidden_in_update=True,
            value_setter=set_user_password,
        ),
        "new_password": FieldConfig(
            input_kind="password",
            hidden_in_create=True,
            value_getter=lambda _user: "",
            value_setter=set_user_password,
        ),
    },
)

If create requires hidden service fields, use create_item_factory.

from xladmin import ModelConfig


def create_admin_user(payload, session, user):
    del payload, session, user
    return UserORM(
        date_joined=AuthBase.now(),
        secret_key=AuthBase.generate_secret_key(),
    )


ModelConfig(
    model=UserORM,
    create_fields=("username", "email", "password"),
    create_item_factory=create_admin_user,
)

If create needs a fully custom form and payload handler, use create_form + create_handler.

The same FormFieldConfig mechanism is also available for object_actions and bulk_actions via form=.... If an action has no form, the frontend runs it immediately as before.

For datetime inputs the built-in dialog uses the MUI action bar with a localized Today / Сегодня button, which inserts the current date and time.

from xladmin import FormFieldConfig, FormFieldOptionConfig, ModelConfig


async def create_proxy(session, model_config, payload, user):
    del session, model_config, user
    parsed = ProxyBase.parse_raw(f"{payload['scheme']}://{payload['proxy']}")
    return ProxyORM(
        name=parsed.name,
        scheme=parsed.scheme,
        host=parsed.host,
        port=parsed.port,
        username=parsed.username,
        password=parsed.password,
        created_at=ProxyBase.now(),
        updated_at=ProxyBase.now(),
    )


ModelConfig(
    model=ProxyORM,
    create_form=(
        FormFieldConfig(
            name="scheme",
            label="Scheme",
            input_kind="select",
            required=True,
            options=(
                FormFieldOptionConfig(value="http", label="HTTP"),
                FormFieldOptionConfig(value="socks5h", label="SOCKS5H"),
            ),
        ),
        FormFieldConfig(
            name="proxy",
            label="Proxy",
            placeholder="login:password@ip:port",
            required=True,
        ),
    ),
    create_handler=create_proxy,
)

Compatibility

  • FastAPI >=0.115,<1.0
  • Pydantic >=2.9,<3.0
  • SQLAlchemy >=2.0,<3.0
  • Python >=3.12

Development

uv sync --extra dev
uv run pytest
uv run ruff check .
uv run mypy
uv run python -m build
uv run python -m twine check dist/*

Docs

Release files for xladmin 0.10.0

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

Source distribution (sdist)

Source distribution for xladmin 0.10.0
File Size Uploaded
xladmin-0.10.0.tar.gz 40.5 kB Details

Built distribution (wheel)

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

Total release size: 73.6 kB

Release files / xladmin-0.10.0.tar.gz

Download URL xladmin-0.10.0.tar.gz
Size 40.5 kB
Tags Source
SHA-256 checksum
How to use checksums
5e6b5d744f042e4f6f653792a3288f6f82b0db8443a5ffb3065b5d0b7375ae60
BLAKE2b-256 checksum
How to use checksums
c0d4b5317fc35f64604e319d075e79454a8a49d79c1beac45a5a2372ba9ad9e6
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.12.14

Release files / xladmin-0.10.0-py3-none-any.whl

Download URL xladmin-0.10.0-py3-none-any.whl
Size 33.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ccb77e8054ad0848573d8c2adda04c46987795bbac7eeab5734eb4fd9b152c18
BLAKE2b-256 checksum
How to use checksums
b7894c7c3da004e02097021475904c3832b0380f84bdbba0985b913dd8defc2c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.12.14

Release history Release notifications | RSS feed

This release

0.10.0 This release

2 release files

0.9.0

2 release files

0.6.0

2 release files

0.4.0

2 release files

0.3.7

2 release files

0.3.6

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.9

2 release files

0.2.8

2 release files

0.2.7

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.4

2 release files

0.1.0

2 release files

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