Architecture

FastAPI Mongo Admin follows a layered architecture inspired by Django’s admin, adapted for MongoDB document stores.

High-level overview

FastAPI App
    │
    ├── mount_admin_app()
    │       │
    │       ├── create_admin_router()     ← routes, Jinja2, HTMX
    │       │       ├── AdminSite         ← model registry
    │       │       ├── ModelAdmin        ← per-model config + hooks
    │       │       └── CollectionRepository
    │       │               ├── AsyncMotorBackend  (mode="async")
    │       │               └── SyncPyMongoBackend (mode="sync")
    │       │
    │       └── StaticFiles (/admin/static/)
    │
    └── Your application routes

Core components

AdminSite

Central registry. Maps collection_nameModelAdmin instance. Supports custom views, template directories, and site branding.

ModelAdmin

Per-model configuration: list display, filters, fieldsets, permissions, hooks, and bulk actions. Subclass and override methods for customization.

CollectionRepository

CRUD operations with field mapping translation, Pydantic validation, list_select_related lookups, and changelist query building.

List filters

Sidebar filters on the changelist. Resolved from field names or custom ListFilter subclasses. Combined into a MongoDB query fragment.

Schema inference

Pydantic model fields are inspected to infer form widgets (text, number, checkbox, JSON editor, date, etc.) and validate submitted form data.

Request flow: changelist

  1. User visits GET /admin/{collection}/

  2. Router resolves ModelAdmin from AdminSite registry

  3. CollectionRepository.list_documents() builds query from: - get_queryset() hook (base filter) - Search fields ($or regex on configured fields) - Active list filters (sidebar) - Date hierarchy params (year, month, day)

  4. Results are serialized (BSON → JSON-safe), related docs resolved

  5. build_changelist_context() prepares Jinja2 context

  6. Template renders (full page or HTMX partial for pagination)

Request flow: add/change form

  1. GET renders form with fieldsets from get_fieldsets()

  2. POST parses multipart form data

  3. CSRF token verified (when session middleware is enabled)

  4. parse_form_to_model() validates through Pydantic

  5. save_model() hook mutates data before persistence

  6. translate_to_db() applies field mapping

  7. prepare_for_mongodb() converts Decimals, dates, etc.

  8. Backend inserts or updates the document

  9. Redirect to changelist with flash cookies (type + object_repr label)

  10. Changelist renders a one-time success banner and clears flash cookies

HTMX integration

The changelist uses HTMX for partial page updates. When an HTMX request is detected (HX-Request header), only the result table partial is returned instead of the full page. This enables fast pagination and filtering without full page reloads.

Template resolution

Jinja2 searches template directories in this order:

  1. Directories passed to AdminSite(template_dirs=[...])

  2. Bundled package templates in fastapi_mongo_admin/templates/

Per-model template overrides (change_list_template, etc.) reference paths relative to these search directories.