FastAPI Mongo Admin
A Django-inspired, server-rendered admin framework for FastAPI and MongoDB.
v2.0.0 replaces the legacy React SPA with a Jinja2 + HTMX admin interface, a full ModelAdmin configuration API, pluggable authentication, and support for both async (Motor) and sync (PyMongo) MongoDB backends.
Screenshots
Key Features
- Django-like registry —
site.register(Model, AdminClass) - Server-rendered admin UI — changelist, add/change forms, delete confirmation, bulk actions
- List filters — choice, boolean, date, related, and custom
ListFilterclasses - Pydantic-driven forms — validation and schema inference from your models
- Field mapping — map model fields to different MongoDB keys
- Pluggable auth — wire any FastAPI
Dependsauthentication/authorization - Sync + async MongoDB —
mode="async"(Motor) ormode="sync"(PyMongo) - Customization — template overrides,
ModelAdminhooks, custom admin views - JSON API —
/admin/api/{collection}/for programmatic access (read-only by default; optional write methods for/docs)
Breaking Changes (v0.x → v2)
- React UI and
/admin-uimount removed; admin lives at/admin MongoAdminalias removed; useAdminSiteorsite- Built-in demo token auth removed; provide
auth_dependency - Legacy
/admin/collections/.../documentsroutes removed
Installation
# Using uv (recommended)
uv add fastapi-mongo-admin
# Or pip
pip install fastapi-mongo-admin
Quick Start
1. Define models and admin classes
from pydantic import BaseModel
from fastapi_mongo_admin import ModelAdmin, site, display, action
from fastapi_mongo_admin.admin.filters import ChoiceListFilter, DateFieldListFilter
class Product(BaseModel):
name: str
price: float
category: str
active: bool = True
class ProductAdmin(ModelAdmin):
model = Product
collection_name = "products"
list_display = ["name", "category", "price", "active"]
list_filter = ["category", "active"]
search_fields = ["name", "category"]
list_per_page = 25
choices = {
"category": [("books", "Books"), ("electronics", "Electronics")],
}
@display(description="Name")
def name_upper(self, obj: dict) -> str:
return str(obj.get("name", "")).upper()
@action("Deactivate selected")
async def deactivate_selected(self, request, queryset: list[dict]) -> None:
pass
site.register(Product, ProductAdmin)
2. Mount in FastAPI (async)
from fastapi import FastAPI
from motor.motor_asyncio import AsyncIOMotorClient
from fastapi_mongo_admin import mount_admin_app
app = FastAPI()
client = AsyncIOMotorClient("mongodb://localhost:27017")
database = client["my_db"]
async def get_database():
return database
mount_admin_app(app, get_database, admin_site=site, mode="async")
3. Sync MongoDB
from pymongo import MongoClient
from fastapi_mongo_admin import mount_admin_app
client = MongoClient("mongodb://localhost:27017")
db = client["my_db"]
mount_admin_app(app, lambda: db, admin_site=site, mode="sync")
Visit http://localhost:8000/admin/ for the admin index.
Authentication
Pass any FastAPI-compatible dependency:
from fastapi import Depends, HTTPException
async def get_admin_user():
# Your JWT/session validation here
return {"id": "user-1", "is_staff": True}
mount_admin_app(
app,
get_database,
admin_site=site,
auth_dependency=get_admin_user,
)
JSON API
Read endpoints are always available at /admin/api/{collection}/. By default only GET operations appear in OpenAPI (/docs).
Enable POST, PUT, PATCH, and DELETE routes (and Swagger documentation):
mount_admin_app(
app,
get_database,
admin_site=site,
auth_dependency=get_admin_user,
api_write_methods=True,
)
| Method | URL | Description |
|---|---|---|
GET |
/admin/api/{collection}/ |
Paginated list (page, q) |
GET |
/admin/api/{collection}/{id} |
Single document |
POST |
/admin/api/{collection}/ |
Create (when api_write_methods=True) |
PUT |
/admin/api/{collection}/{id} |
Update |
PATCH |
/admin/api/{collection}/{id} |
Partial update |
DELETE |
/admin/api/{collection}/{id} |
Delete |
Write requests use the same Pydantic validation and ModelAdmin permission hooks as the HTML admin.
Override per-model permissions on ModelAdmin:
class ProductAdmin(ModelAdmin):
def has_add_permission(self, request, user=None) -> bool:
return bool(user and user.get("is_staff"))
ModelAdmin Options
| Option | Description |
|---|---|
model |
Pydantic model for validation |
collection_name |
MongoDB collection (required) |
list_display |
Changelist columns (fields or @display methods) |
list_display_links |
Clickable columns |
list_filter |
Field names or ListFilter subclasses |
search_fields |
Text search fields |
list_per_page |
Pagination size (default 25) |
ordering |
Default sort, e.g. ["-created_at"] |
date_hierarchy |
Date drill-down field |
list_select_related |
{"field": "collection"} for related lookups |
fieldsets |
Grouped change form layout |
readonly_fields |
Non-editable fields |
field_mapping |
Model field → DB field mapping |
actions |
Bulk action method names |
choices |
Choice lookups for filters/forms |
date_format |
Display format for date fields (default: 8 Apr 2026) |
datetime_format |
Display format for datetime fields (default: 8 Apr 2026, 7:32pm) |
Date and Time Display
date and datetime fields are formatted automatically on changelists and readonly form fields. Form inputs still use ISO values for HTML date/datetime pickers.
Default formats:
- Date:
8 Apr 2026 - Datetime:
8 Apr 2026, 7:32pm
Customize per model:
class OrderAdmin(ModelAdmin):
date_format = "j M Y" # Django-style tokens
datetime_format = "%d/%m/%Y %H:%M" # or standard strftime
Override completely:
def format_datetime_value(self, value) -> str:
return my_formatter(value)
Template Customization
from pathlib import Path
site = AdminSite(template_dirs=[Path("myapp/templates")])
class ProductAdmin(ModelAdmin):
change_list_template = "myapp/admin/product_change_list.html"
Register custom views:
async def reports(request):
return {"report": "data"}
site.register_view("Reports", "/reports/", reports)
URL Scheme
| URL | View |
|---|---|
GET /admin/ |
Admin index |
GET /admin/{collection}/ |
Changelist |
GET /admin/{collection}/add/ |
Add form |
GET/POST /admin/{collection}/{id}/change/ |
Change form |
POST /admin/{collection}/{id}/delete/ |
Delete |
POST /admin/{collection}/action/ |
Bulk actions |
GET /admin/api/{collection}/ |
JSON list API |
GET /admin/api/{collection}/{id} |
JSON detail API |
POST/PUT/PATCH/DELETE /admin/api/... |
JSON write API (api_write_methods=True) |
Development
make install # uv sync --group dev
make test # pytest
make lint # ruff
make secure # bandit + pysentry-rs
make docs # build Sphinx HTML docs
make help # list all targets
License
MIT
Metadata
Release files for fastapi-mongo-admin 2.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| fastapi_mongo_admin-2.0.2.tar.gz | 527.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| fastapi_mongo_admin-2.0.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 1.1 MB
Release files / fastapi_mongo_admin-2.0.2.tar.gz
| Download URL | fastapi_mongo_admin-2.0.2.tar.gz |
|---|---|
| Size | 527.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cf5dbfa7e5d855ad373482c6d711eb2bf69d59a2d2f7e15893586427926756f7
|
|
BLAKE2b-256 checksum How to use checksums |
df77e69409200793b19a721c8336e615fdb04bba5206b0113794d0addfa723d2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.11
|
Release files / fastapi_mongo_admin-2.0.2-py3-none-any.whl
| Download URL | fastapi_mongo_admin-2.0.2-py3-none-any.whl |
|---|---|
| Size | 537.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
9d94e34c68f3f8385b3c24548e0fd19ecf5d9ebf6874b3957778e28402da9400
|
|
BLAKE2b-256 checksum How to use checksums |
469d7c41fb06b57248a717a4fac796285fee3d655d0ce31264f78132d4ef66c9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.12.11
|