fastadmin 0.4.9__tar.gz → 0.6.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- fastadmin-0.6.0/PKG-INFO +215 -0
- fastadmin-0.6.0/README.md +169 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/app/api.py +8 -2
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/fastapi/api.py +8 -2
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/fastapi/app.py +3 -1
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/flask/api.py +9 -3
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/helpers.py +2 -9
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/service.py +83 -28
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/base.py +50 -9
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/decorators.py +1 -1
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/helpers.py +1 -1
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/ponyorm.py +39 -30
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/sqlalchemy.py +33 -13
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/settings.py +13 -1
- fastadmin-0.6.0/fastadmin/static/index.min.js +653 -0
- fastadmin-0.6.0/pyproject.toml +153 -0
- fastadmin-0.4.9/PKG-INFO +0 -877
- fastadmin-0.4.9/README.md +0 -834
- fastadmin-0.4.9/fastadmin/static/index.min.js +0 -680
- fastadmin-0.4.9/pyproject.toml +0 -150
- /fastadmin-0.4.9/LICENSE → /fastadmin-0.6.0/LICENSE.md +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/exceptions.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/app/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/app/urls.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/app/views.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/fastapi/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/fastapi/views.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/flask/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/flask/app.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/flask/views.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/schemas.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/__init__.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/django.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/tortoise.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/schemas.py +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-6Z7niv9l.js +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-C151k0-L.js +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-C9KPOOKD.js +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-D1fCgYB7.js +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-D3TWcJOI.js +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-DRNcaZ-V.js +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-MF2p-l5_.js +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/images/favicon.png +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/images/header-logo.svg +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/images/sign-in-logo.svg +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/index.html +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/index.min.css +0 -0
- {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/templates/index.html +0 -0
fastadmin-0.6.0/PKG-INFO
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: fastadmin
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: FastAdmin is an easy-to-use Admin Dashboard App for FastAPI/Flask/Django inspired by Django Admin.
|
|
5
|
+
Keywords: admin,dashboard,fastapi,flask,django,tortoise-orm,sqlalchemy,pony,admin-dashboard,django-admin
|
|
6
|
+
Author: Seva D
|
|
7
|
+
Author-email: Seva D <vsdudakov@gmail.com>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE.md
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Environment :: Console
|
|
12
|
+
Classifier: Framework :: FastAPI
|
|
13
|
+
Classifier: Framework :: Django
|
|
14
|
+
Classifier: Framework :: Flask
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Operating System :: OS Independent
|
|
17
|
+
Classifier: Programming Language :: Python :: 3
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Topic :: Software Development :: Documentation
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: Software Development :: Widget Sets
|
|
23
|
+
Classifier: Typing :: Typed
|
|
24
|
+
Requires-Dist: pyjwt>=2.6
|
|
25
|
+
Requires-Dist: asgiref>=3.11
|
|
26
|
+
Requires-Dist: django>=6,<7 ; extra == 'django'
|
|
27
|
+
Requires-Dist: fastapi>=0.100,<1 ; extra == 'fastapi'
|
|
28
|
+
Requires-Dist: python-multipart>=0.0.5,<1 ; extra == 'fastapi'
|
|
29
|
+
Requires-Dist: flask>=3,<4 ; extra == 'flask'
|
|
30
|
+
Requires-Dist: pony>=0.7,<1 ; extra == 'pony'
|
|
31
|
+
Requires-Dist: sqlalchemy[asyncio]>=2,<3 ; extra == 'sqlalchemy'
|
|
32
|
+
Requires-Dist: greenlet>=3 ; extra == 'sqlalchemy'
|
|
33
|
+
Requires-Dist: tortoise-orm>=1,<2 ; extra == 'tortoise-orm'
|
|
34
|
+
Requires-Python: >=3.12
|
|
35
|
+
Project-URL: Homepage, https://vsdudakov.github.io/fastadmin/
|
|
36
|
+
Project-URL: Repository, https://github.com/vsdudakov/fastadmin
|
|
37
|
+
Project-URL: Documentation, https://vsdudakov.github.io/fastadmin/
|
|
38
|
+
Project-URL: Issues, https://github.com/vsdudakov/fastadmin/issues
|
|
39
|
+
Provides-Extra: django
|
|
40
|
+
Provides-Extra: fastapi
|
|
41
|
+
Provides-Extra: flask
|
|
42
|
+
Provides-Extra: pony
|
|
43
|
+
Provides-Extra: sqlalchemy
|
|
44
|
+
Provides-Extra: tortoise-orm
|
|
45
|
+
Description-Content-Type: text/markdown
|
|
46
|
+
|
|
47
|
+
<h1 align="center">FastAdmin — Admin Dashboard for FastAPI, Flask and Django</h1>
|
|
48
|
+
|
|
49
|
+
<p align="center">
|
|
50
|
+
<a href="https://github.com/vsdudakov/fastadmin/actions/workflows/ci.yml"><img src="https://github.com/vsdudakov/fastadmin/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
51
|
+
<a href="https://app.codecov.io/gh/vsdudakov/fastadmin"><img src="https://codecov.io/gh/vsdudakov/fastadmin/branch/main/graph/badge.svg?token=RNGX5HOW3T" alt="codecov"></a>
|
|
52
|
+
<a href="https://pypi.org/project/fastadmin/"><img src="https://badgen.net/pypi/v/fastadmin" alt="PyPI"></a>
|
|
53
|
+
<a href="https://pypi.org/project/fastadmin/"><img src="https://img.shields.io/badge/python-3.12%2B-blue.svg" alt="Python 3.12+"></a>
|
|
54
|
+
<a href="https://github.com/vsdudakov/fastadmin/blob/main/LICENSE.md"><img src="https://img.shields.io/github/license/vsdudakov/fastadmin" alt="License: MIT"></a>
|
|
55
|
+
</p>
|
|
56
|
+
|
|
57
|
+
**FastAdmin** is an easy-to-use **admin dashboard (admin panel) for FastAPI, Flask and
|
|
58
|
+
Django**, inspired by Django Admin. It gives your Python web application a
|
|
59
|
+
production-ready **CRUD admin interface** in minutes — on top of **Tortoise ORM,
|
|
60
|
+
Django ORM, SQLAlchemy or Pony ORM** — with authentication, filters, search,
|
|
61
|
+
inline editing, file uploads, CSV/JSON export and dashboard charts out of the box.
|
|
62
|
+
|
|
63
|
+
FastAdmin is built with relationships in mind and admiration for Django Admin.
|
|
64
|
+
It aims to be minimal, functional and familiar: if you know Django Admin, you
|
|
65
|
+
already know FastAdmin.
|
|
66
|
+
|
|
67
|
+
📚 **Documentation: [https://vsdudakov.github.io/fastadmin/](https://vsdudakov.github.io/fastadmin/)**
|
|
68
|
+
|
|
69
|
+
## Demo
|
|
70
|
+
|
|
71
|
+

|
|
72
|
+
|
|
73
|
+
## Features
|
|
74
|
+
|
|
75
|
+
- **Familiar Django-Admin-style API** — `list_display`, `list_filter`,
|
|
76
|
+
`search_fields`, `fieldsets`, `readonly_fields`, inlines, actions and more.
|
|
77
|
+
- **Any web framework** — mount as a FastAPI sub-app, a Flask blueprint or
|
|
78
|
+
Django urlpatterns.
|
|
79
|
+
- **Any ORM** — first-class admin classes for Tortoise ORM, Django ORM,
|
|
80
|
+
SQLAlchemy (async) and Pony ORM.
|
|
81
|
+
- **Authentication & permissions** — pluggable sign-in against your own user
|
|
82
|
+
model, per-action permission hooks, request/user context in every admin method.
|
|
83
|
+
- **Rich form widgets** — 20+ antd-based widgets (rich text, JSON, async
|
|
84
|
+
select, phone, slug, date/time pickers, switches, radio groups, …) via
|
|
85
|
+
`formfield_overrides`.
|
|
86
|
+
- **File & image uploads** — storage-agnostic `upload_file` hook and
|
|
87
|
+
presigned-URL support via `get_file_url` (local disk, S3, …).
|
|
88
|
+
- **Dashboard widgets** — declarative line/area/column/bar/pie charts and
|
|
89
|
+
action widgets with filters, powered by antd charts.
|
|
90
|
+
- **Bulk actions & export** — custom bulk actions, CSV/JSON export.
|
|
91
|
+
- **Quality** — fully typed and linted (ruff + ty), 100% backend test coverage,
|
|
92
|
+
modern React (Vite + antd) frontend bundled with the package — no Node.js
|
|
93
|
+
needed at install time.
|
|
94
|
+
|
|
95
|
+
## Installation
|
|
96
|
+
|
|
97
|
+
Install with the extras matching your web framework and ORM (each combination
|
|
98
|
+
works standalone):
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
pip install fastadmin[fastapi,django] # FastAPI with Django ORM
|
|
102
|
+
pip install fastadmin[fastapi,tortoise-orm] # FastAPI with Tortoise ORM
|
|
103
|
+
pip install fastadmin[fastapi,pony] # FastAPI with Pony ORM
|
|
104
|
+
pip install fastadmin[fastapi,sqlalchemy] # FastAPI with SQLAlchemy (includes greenlet)
|
|
105
|
+
pip install fastadmin[django] # Django with Django ORM
|
|
106
|
+
pip install fastadmin[django,pony] # Django with Pony ORM
|
|
107
|
+
pip install fastadmin[flask,sqlalchemy] # Flask with SQLAlchemy (includes greenlet)
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
> **Note:** on zsh (the default macOS shell) quote the extras: `pip install 'fastadmin[fastapi,django]'`.
|
|
111
|
+
|
|
112
|
+
Configure the required settings:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
export ADMIN_USER_MODEL=User
|
|
116
|
+
export ADMIN_USER_MODEL_USERNAME_FIELD=username
|
|
117
|
+
export ADMIN_SECRET_KEY=secret_key
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Quick start
|
|
121
|
+
|
|
122
|
+
```python
|
|
123
|
+
import bcrypt
|
|
124
|
+
from fastapi import FastAPI
|
|
125
|
+
|
|
126
|
+
from fastadmin import TortoiseModelAdmin, register
|
|
127
|
+
from fastadmin import fastapi_app as admin_app
|
|
128
|
+
|
|
129
|
+
from models import User
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
@register(User)
|
|
133
|
+
class UserAdmin(TortoiseModelAdmin):
|
|
134
|
+
exclude = ("hash_password",)
|
|
135
|
+
list_display = ("id", "username", "is_superuser", "is_active")
|
|
136
|
+
list_display_links = ("id", "username")
|
|
137
|
+
list_filter = ("id", "username", "is_superuser", "is_active")
|
|
138
|
+
search_fields = ("username",)
|
|
139
|
+
|
|
140
|
+
async def authenticate(self, username: str, password: str) -> int | None:
|
|
141
|
+
user = await User.filter(username=username, is_superuser=True).first()
|
|
142
|
+
if not user:
|
|
143
|
+
return None
|
|
144
|
+
if not bcrypt.checkpw(password.encode(), user.hash_password.encode()):
|
|
145
|
+
return None
|
|
146
|
+
return user.id
|
|
147
|
+
|
|
148
|
+
async def change_password(self, id: int, password: str) -> None:
|
|
149
|
+
user = await User.filter(id=id).first()
|
|
150
|
+
if not user:
|
|
151
|
+
return
|
|
152
|
+
user.hash_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
|
|
153
|
+
await user.save(update_fields=("hash_password",))
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
app = FastAPI()
|
|
157
|
+
app.mount("/admin", admin_app)
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Run `uvicorn example:app` and open `http://localhost:8000/admin`.
|
|
161
|
+
|
|
162
|
+
Mounting for the other frameworks:
|
|
163
|
+
|
|
164
|
+
```python
|
|
165
|
+
# Flask
|
|
166
|
+
from fastadmin import flask_app as admin_app
|
|
167
|
+
app.register_blueprint(admin_app, url_prefix="/admin")
|
|
168
|
+
|
|
169
|
+
# Django (urls.py)
|
|
170
|
+
from fastadmin import get_django_admin_urls as get_admin_urls
|
|
171
|
+
urlpatterns = [path("admin/", get_admin_urls())]
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
## Documentation
|
|
175
|
+
|
|
176
|
+
Full documentation lives at
|
|
177
|
+
**[vsdudakov.github.io/fastadmin](https://vsdudakov.github.io/fastadmin/)**:
|
|
178
|
+
|
|
179
|
+
- [Installation](https://vsdudakov.github.io/fastadmin/getting-started/installation/)
|
|
180
|
+
and [Quick start](https://vsdudakov.github.io/fastadmin/getting-started/quickstart/)
|
|
181
|
+
- [Settings](https://vsdudakov.github.io/fastadmin/guides/settings/) — all environment variables
|
|
182
|
+
- [Registering models](https://vsdudakov.github.io/fastadmin/guides/registering-models/) — complete runnable examples for all four ORMs
|
|
183
|
+
- [Authentication](https://vsdudakov.github.io/fastadmin/guides/authentication/) and permissions
|
|
184
|
+
- [Model admins](https://vsdudakov.github.io/fastadmin/guides/model-admins/) — attributes, actions, display fields, exports
|
|
185
|
+
- [Form widgets & file uploads](https://vsdudakov.github.io/fastadmin/guides/form-widgets/)
|
|
186
|
+
- [Inline admins](https://vsdudakov.github.io/fastadmin/guides/inline-admins/)
|
|
187
|
+
- [Dashboard widgets](https://vsdudakov.github.io/fastadmin/guides/dashboard-widgets/) — charts and actions
|
|
188
|
+
- [API reference](https://vsdudakov.github.io/fastadmin/api-reference/)
|
|
189
|
+
|
|
190
|
+
Runnable example apps for every framework/ORM combination are in
|
|
191
|
+
[`examples/`](https://github.com/vsdudakov/fastadmin/tree/main/examples).
|
|
192
|
+
|
|
193
|
+
## Why FastAdmin?
|
|
194
|
+
|
|
195
|
+
If you are looking for a **Django-Admin-like admin panel for FastAPI**, an
|
|
196
|
+
**admin interface for SQLAlchemy or Tortoise ORM**, or a lightweight
|
|
197
|
+
**alternative to building a custom back office**, FastAdmin gives you a
|
|
198
|
+
batteries-included, themeable admin UI without code generation, without tying
|
|
199
|
+
your app to a specific framework, and without writing a single React component.
|
|
200
|
+
|
|
201
|
+
## Contributing
|
|
202
|
+
|
|
203
|
+
Contributions are welcome — see the
|
|
204
|
+
[contributing guide](https://vsdudakov.github.io/fastadmin/contributing/).
|
|
205
|
+
Development uses `uv` and `make`: `make dev`, `make lint`, `make test`.
|
|
206
|
+
See [CHANGELOG.md](https://github.com/vsdudakov/fastadmin/blob/main/CHANGELOG.md)
|
|
207
|
+
for release history.
|
|
208
|
+
|
|
209
|
+
If you have questions beyond the documentation, feel free to
|
|
210
|
+
[email us](mailto:vsdudakov@gmail.com).
|
|
211
|
+
|
|
212
|
+
## License
|
|
213
|
+
|
|
214
|
+
FastAdmin is released under the
|
|
215
|
+
[MIT License](https://github.com/vsdudakov/fastadmin/blob/main/LICENSE.md).
|
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
<h1 align="center">FastAdmin — Admin Dashboard for FastAPI, Flask and Django</h1>
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<a href="https://github.com/vsdudakov/fastadmin/actions/workflows/ci.yml"><img src="https://github.com/vsdudakov/fastadmin/actions/workflows/ci.yml/badge.svg" alt="CI"></a>
|
|
5
|
+
<a href="https://app.codecov.io/gh/vsdudakov/fastadmin"><img src="https://codecov.io/gh/vsdudakov/fastadmin/branch/main/graph/badge.svg?token=RNGX5HOW3T" alt="codecov"></a>
|
|
6
|
+
<a href="https://pypi.org/project/fastadmin/"><img src="https://badgen.net/pypi/v/fastadmin" alt="PyPI"></a>
|
|
7
|
+
<a href="https://pypi.org/project/fastadmin/"><img src="https://img.shields.io/badge/python-3.12%2B-blue.svg" alt="Python 3.12+"></a>
|
|
8
|
+
<a href="https://github.com/vsdudakov/fastadmin/blob/main/LICENSE.md"><img src="https://img.shields.io/github/license/vsdudakov/fastadmin" alt="License: MIT"></a>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
**FastAdmin** is an easy-to-use **admin dashboard (admin panel) for FastAPI, Flask and
|
|
12
|
+
Django**, inspired by Django Admin. It gives your Python web application a
|
|
13
|
+
production-ready **CRUD admin interface** in minutes — on top of **Tortoise ORM,
|
|
14
|
+
Django ORM, SQLAlchemy or Pony ORM** — with authentication, filters, search,
|
|
15
|
+
inline editing, file uploads, CSV/JSON export and dashboard charts out of the box.
|
|
16
|
+
|
|
17
|
+
FastAdmin is built with relationships in mind and admiration for Django Admin.
|
|
18
|
+
It aims to be minimal, functional and familiar: if you know Django Admin, you
|
|
19
|
+
already know FastAdmin.
|
|
20
|
+
|
|
21
|
+
📚 **Documentation: [https://vsdudakov.github.io/fastadmin/](https://vsdudakov.github.io/fastadmin/)**
|
|
22
|
+
|
|
23
|
+
## Demo
|
|
24
|
+
|
|
25
|
+

|
|
26
|
+
|
|
27
|
+
## Features
|
|
28
|
+
|
|
29
|
+
- **Familiar Django-Admin-style API** — `list_display`, `list_filter`,
|
|
30
|
+
`search_fields`, `fieldsets`, `readonly_fields`, inlines, actions and more.
|
|
31
|
+
- **Any web framework** — mount as a FastAPI sub-app, a Flask blueprint or
|
|
32
|
+
Django urlpatterns.
|
|
33
|
+
- **Any ORM** — first-class admin classes for Tortoise ORM, Django ORM,
|
|
34
|
+
SQLAlchemy (async) and Pony ORM.
|
|
35
|
+
- **Authentication & permissions** — pluggable sign-in against your own user
|
|
36
|
+
model, per-action permission hooks, request/user context in every admin method.
|
|
37
|
+
- **Rich form widgets** — 20+ antd-based widgets (rich text, JSON, async
|
|
38
|
+
select, phone, slug, date/time pickers, switches, radio groups, …) via
|
|
39
|
+
`formfield_overrides`.
|
|
40
|
+
- **File & image uploads** — storage-agnostic `upload_file` hook and
|
|
41
|
+
presigned-URL support via `get_file_url` (local disk, S3, …).
|
|
42
|
+
- **Dashboard widgets** — declarative line/area/column/bar/pie charts and
|
|
43
|
+
action widgets with filters, powered by antd charts.
|
|
44
|
+
- **Bulk actions & export** — custom bulk actions, CSV/JSON export.
|
|
45
|
+
- **Quality** — fully typed and linted (ruff + ty), 100% backend test coverage,
|
|
46
|
+
modern React (Vite + antd) frontend bundled with the package — no Node.js
|
|
47
|
+
needed at install time.
|
|
48
|
+
|
|
49
|
+
## Installation
|
|
50
|
+
|
|
51
|
+
Install with the extras matching your web framework and ORM (each combination
|
|
52
|
+
works standalone):
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
pip install fastadmin[fastapi,django] # FastAPI with Django ORM
|
|
56
|
+
pip install fastadmin[fastapi,tortoise-orm] # FastAPI with Tortoise ORM
|
|
57
|
+
pip install fastadmin[fastapi,pony] # FastAPI with Pony ORM
|
|
58
|
+
pip install fastadmin[fastapi,sqlalchemy] # FastAPI with SQLAlchemy (includes greenlet)
|
|
59
|
+
pip install fastadmin[django] # Django with Django ORM
|
|
60
|
+
pip install fastadmin[django,pony] # Django with Pony ORM
|
|
61
|
+
pip install fastadmin[flask,sqlalchemy] # Flask with SQLAlchemy (includes greenlet)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
> **Note:** on zsh (the default macOS shell) quote the extras: `pip install 'fastadmin[fastapi,django]'`.
|
|
65
|
+
|
|
66
|
+
Configure the required settings:
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
export ADMIN_USER_MODEL=User
|
|
70
|
+
export ADMIN_USER_MODEL_USERNAME_FIELD=username
|
|
71
|
+
export ADMIN_SECRET_KEY=secret_key
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
## Quick start
|
|
75
|
+
|
|
76
|
+
```python
|
|
77
|
+
import bcrypt
|
|
78
|
+
from fastapi import FastAPI
|
|
79
|
+
|
|
80
|
+
from fastadmin import TortoiseModelAdmin, register
|
|
81
|
+
from fastadmin import fastapi_app as admin_app
|
|
82
|
+
|
|
83
|
+
from models import User
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
@register(User)
|
|
87
|
+
class UserAdmin(TortoiseModelAdmin):
|
|
88
|
+
exclude = ("hash_password",)
|
|
89
|
+
list_display = ("id", "username", "is_superuser", "is_active")
|
|
90
|
+
list_display_links = ("id", "username")
|
|
91
|
+
list_filter = ("id", "username", "is_superuser", "is_active")
|
|
92
|
+
search_fields = ("username",)
|
|
93
|
+
|
|
94
|
+
async def authenticate(self, username: str, password: str) -> int | None:
|
|
95
|
+
user = await User.filter(username=username, is_superuser=True).first()
|
|
96
|
+
if not user:
|
|
97
|
+
return None
|
|
98
|
+
if not bcrypt.checkpw(password.encode(), user.hash_password.encode()):
|
|
99
|
+
return None
|
|
100
|
+
return user.id
|
|
101
|
+
|
|
102
|
+
async def change_password(self, id: int, password: str) -> None:
|
|
103
|
+
user = await User.filter(id=id).first()
|
|
104
|
+
if not user:
|
|
105
|
+
return
|
|
106
|
+
user.hash_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
|
|
107
|
+
await user.save(update_fields=("hash_password",))
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
app = FastAPI()
|
|
111
|
+
app.mount("/admin", admin_app)
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Run `uvicorn example:app` and open `http://localhost:8000/admin`.
|
|
115
|
+
|
|
116
|
+
Mounting for the other frameworks:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
# Flask
|
|
120
|
+
from fastadmin import flask_app as admin_app
|
|
121
|
+
app.register_blueprint(admin_app, url_prefix="/admin")
|
|
122
|
+
|
|
123
|
+
# Django (urls.py)
|
|
124
|
+
from fastadmin import get_django_admin_urls as get_admin_urls
|
|
125
|
+
urlpatterns = [path("admin/", get_admin_urls())]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Documentation
|
|
129
|
+
|
|
130
|
+
Full documentation lives at
|
|
131
|
+
**[vsdudakov.github.io/fastadmin](https://vsdudakov.github.io/fastadmin/)**:
|
|
132
|
+
|
|
133
|
+
- [Installation](https://vsdudakov.github.io/fastadmin/getting-started/installation/)
|
|
134
|
+
and [Quick start](https://vsdudakov.github.io/fastadmin/getting-started/quickstart/)
|
|
135
|
+
- [Settings](https://vsdudakov.github.io/fastadmin/guides/settings/) — all environment variables
|
|
136
|
+
- [Registering models](https://vsdudakov.github.io/fastadmin/guides/registering-models/) — complete runnable examples for all four ORMs
|
|
137
|
+
- [Authentication](https://vsdudakov.github.io/fastadmin/guides/authentication/) and permissions
|
|
138
|
+
- [Model admins](https://vsdudakov.github.io/fastadmin/guides/model-admins/) — attributes, actions, display fields, exports
|
|
139
|
+
- [Form widgets & file uploads](https://vsdudakov.github.io/fastadmin/guides/form-widgets/)
|
|
140
|
+
- [Inline admins](https://vsdudakov.github.io/fastadmin/guides/inline-admins/)
|
|
141
|
+
- [Dashboard widgets](https://vsdudakov.github.io/fastadmin/guides/dashboard-widgets/) — charts and actions
|
|
142
|
+
- [API reference](https://vsdudakov.github.io/fastadmin/api-reference/)
|
|
143
|
+
|
|
144
|
+
Runnable example apps for every framework/ORM combination are in
|
|
145
|
+
[`examples/`](https://github.com/vsdudakov/fastadmin/tree/main/examples).
|
|
146
|
+
|
|
147
|
+
## Why FastAdmin?
|
|
148
|
+
|
|
149
|
+
If you are looking for a **Django-Admin-like admin panel for FastAPI**, an
|
|
150
|
+
**admin interface for SQLAlchemy or Tortoise ORM**, or a lightweight
|
|
151
|
+
**alternative to building a custom back office**, FastAdmin gives you a
|
|
152
|
+
batteries-included, themeable admin UI without code generation, without tying
|
|
153
|
+
your app to a specific framework, and without writing a single React component.
|
|
154
|
+
|
|
155
|
+
## Contributing
|
|
156
|
+
|
|
157
|
+
Contributions are welcome — see the
|
|
158
|
+
[contributing guide](https://vsdudakov.github.io/fastadmin/contributing/).
|
|
159
|
+
Development uses `uv` and `make`: `make dev`, `make lint`, `make test`.
|
|
160
|
+
See [CHANGELOG.md](https://github.com/vsdudakov/fastadmin/blob/main/CHANGELOG.md)
|
|
161
|
+
for release history.
|
|
162
|
+
|
|
163
|
+
If you have questions beyond the documentation, feel free to
|
|
164
|
+
[email us](mailto:vsdudakov@gmail.com).
|
|
165
|
+
|
|
166
|
+
## License
|
|
167
|
+
|
|
168
|
+
FastAdmin is released under the
|
|
169
|
+
[MIT License](https://github.com/vsdudakov/fastadmin/blob/main/LICENSE.md).
|
|
@@ -78,7 +78,13 @@ async def sign_in(request: HttpRequest) -> JsonResponse:
|
|
|
78
78
|
)
|
|
79
79
|
|
|
80
80
|
response = JsonResponse({})
|
|
81
|
-
response.set_cookie(
|
|
81
|
+
response.set_cookie(
|
|
82
|
+
settings.ADMIN_SESSION_ID_KEY,
|
|
83
|
+
value=session_id,
|
|
84
|
+
httponly=True,
|
|
85
|
+
secure=settings.ADMIN_SESSION_COOKIE_SECURE,
|
|
86
|
+
samesite=settings.ADMIN_SESSION_COOKIE_SAMESITE.capitalize(),
|
|
87
|
+
)
|
|
82
88
|
return response
|
|
83
89
|
|
|
84
90
|
except AdminApiException as e:
|
|
@@ -317,7 +323,7 @@ async def upload_file(
|
|
|
317
323
|
|
|
318
324
|
|
|
319
325
|
@csrf_exempt
|
|
320
|
-
async def export(request: HttpRequest, model: str) -> JsonResponse:
|
|
326
|
+
async def export(request: HttpRequest, model: str) -> JsonResponse | StreamingHttpResponse:
|
|
321
327
|
"""This method is used to export a list of objects.
|
|
322
328
|
|
|
323
329
|
:params request: a request object.
|
|
@@ -49,7 +49,13 @@ async def sign_in(
|
|
|
49
49
|
request=request,
|
|
50
50
|
)
|
|
51
51
|
|
|
52
|
-
response.set_cookie(
|
|
52
|
+
response.set_cookie(
|
|
53
|
+
settings.ADMIN_SESSION_ID_KEY,
|
|
54
|
+
value=session_id,
|
|
55
|
+
httponly=True,
|
|
56
|
+
secure=settings.ADMIN_SESSION_COOKIE_SECURE,
|
|
57
|
+
samesite=settings.ADMIN_SESSION_COOKIE_SAMESITE, # ty: ignore[invalid-argument-type]
|
|
58
|
+
)
|
|
53
59
|
except AdminApiException as e:
|
|
54
60
|
raise HTTPException(e.status_code, detail=e.detail) from None
|
|
55
61
|
|
|
@@ -307,7 +313,7 @@ async def export(
|
|
|
307
313
|
)
|
|
308
314
|
headers = {"Content-Disposition": f'attachment; filename="{file_name}"'}
|
|
309
315
|
return StreamingResponse(
|
|
310
|
-
stream, #
|
|
316
|
+
stream, # ty: ignore[invalid-argument-type]
|
|
311
317
|
headers=headers,
|
|
312
318
|
media_type=content_type,
|
|
313
319
|
)
|
|
@@ -25,7 +25,9 @@ app.include_router(views_router)
|
|
|
25
25
|
|
|
26
26
|
@app.exception_handler(Exception)
|
|
27
27
|
async def exception_handler(_: Request, exc: Exception):
|
|
28
|
+
# Log the real error server-side but never leak internals to the client.
|
|
29
|
+
logger.error("Unhandled admin error: %s", exc)
|
|
28
30
|
return JSONResponse(
|
|
29
31
|
status_code=500,
|
|
30
|
-
content={"exception":
|
|
32
|
+
content={"exception": "Internal server error."},
|
|
31
33
|
)
|
|
@@ -42,7 +42,13 @@ async def sign_in() -> Response:
|
|
|
42
42
|
request=request,
|
|
43
43
|
)
|
|
44
44
|
response = make_response({})
|
|
45
|
-
response.set_cookie(
|
|
45
|
+
response.set_cookie(
|
|
46
|
+
settings.ADMIN_SESSION_ID_KEY,
|
|
47
|
+
value=session_id,
|
|
48
|
+
httponly=True,
|
|
49
|
+
secure=settings.ADMIN_SESSION_COOKIE_SECURE,
|
|
50
|
+
samesite=settings.ADMIN_SESSION_COOKIE_SAMESITE.capitalize(),
|
|
51
|
+
)
|
|
46
52
|
return response
|
|
47
53
|
except AdminApiException as e:
|
|
48
54
|
http_exception = HTTPException(e.detail)
|
|
@@ -188,7 +194,7 @@ async def add(model: str) -> dict:
|
|
|
188
194
|
raise http_exception from e
|
|
189
195
|
|
|
190
196
|
|
|
191
|
-
@api_router.route("/change-password/<string:id>", methods=["PATCH"]) #
|
|
197
|
+
@api_router.route("/change-password/<string:id>", methods=["PATCH"]) # ty: ignore[invalid-argument-type]
|
|
192
198
|
async def change_password(id: UUID | int | str) -> UUID | int | str:
|
|
193
199
|
"""This method is used to change password.
|
|
194
200
|
|
|
@@ -322,7 +328,7 @@ async def export(model: str) -> Response:
|
|
|
322
328
|
raise http_exception from e
|
|
323
329
|
|
|
324
330
|
|
|
325
|
-
@api_router.route("/delete/<string:model>/<string:id>", methods=["DELETE"]) #
|
|
331
|
+
@api_router.route("/delete/<string:model>/<string:id>", methods=["DELETE"]) # ty: ignore[invalid-argument-type]
|
|
326
332
|
async def delete(
|
|
327
333
|
model: str,
|
|
328
334
|
id: UUID | int | str,
|
|
@@ -84,15 +84,8 @@ def is_valid_id(id: UUID | int | str) -> bool:
|
|
|
84
84
|
:return: True if id is a valid id, False otherwise.
|
|
85
85
|
"""
|
|
86
86
|
if isinstance(id, str):
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
if is_valid_uuid(id):
|
|
90
|
-
return True
|
|
91
|
-
try:
|
|
92
|
-
int(id)
|
|
93
|
-
return True
|
|
94
|
-
except ValueError:
|
|
95
|
-
return True # string PK (e.g. non-numeric)
|
|
87
|
+
# Any non-empty string is a valid PK (UUID, numeric, or opaque string PK).
|
|
88
|
+
return bool(id)
|
|
96
89
|
if is_valid_uuid(str(id)):
|
|
97
90
|
return True
|
|
98
91
|
try:
|