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.
Files changed (53) hide show
  1. fastadmin-0.6.0/PKG-INFO +215 -0
  2. fastadmin-0.6.0/README.md +169 -0
  3. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/app/api.py +8 -2
  4. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/fastapi/api.py +8 -2
  5. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/fastapi/app.py +3 -1
  6. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/flask/api.py +9 -3
  7. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/helpers.py +2 -9
  8. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/service.py +83 -28
  9. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/base.py +50 -9
  10. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/decorators.py +1 -1
  11. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/helpers.py +1 -1
  12. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/ponyorm.py +39 -30
  13. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/sqlalchemy.py +33 -13
  14. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/settings.py +13 -1
  15. fastadmin-0.6.0/fastadmin/static/index.min.js +653 -0
  16. fastadmin-0.6.0/pyproject.toml +153 -0
  17. fastadmin-0.4.9/PKG-INFO +0 -877
  18. fastadmin-0.4.9/README.md +0 -834
  19. fastadmin-0.4.9/fastadmin/static/index.min.js +0 -680
  20. fastadmin-0.4.9/pyproject.toml +0 -150
  21. /fastadmin-0.4.9/LICENSE → /fastadmin-0.6.0/LICENSE.md +0 -0
  22. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/__init__.py +0 -0
  23. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/__init__.py +0 -0
  24. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/exceptions.py +0 -0
  25. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/__init__.py +0 -0
  26. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/__init__.py +0 -0
  27. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/app/__init__.py +0 -0
  28. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/app/urls.py +0 -0
  29. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/django/app/views.py +0 -0
  30. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/fastapi/__init__.py +0 -0
  31. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/fastapi/views.py +0 -0
  32. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/flask/__init__.py +0 -0
  33. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/flask/app.py +0 -0
  34. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/frameworks/flask/views.py +0 -0
  35. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/api/schemas.py +0 -0
  36. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/__init__.py +0 -0
  37. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/__init__.py +0 -0
  38. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/django.py +0 -0
  39. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/orms/tortoise.py +0 -0
  40. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/models/schemas.py +0 -0
  41. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-6Z7niv9l.js +0 -0
  42. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-C151k0-L.js +0 -0
  43. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-C9KPOOKD.js +0 -0
  44. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-D1fCgYB7.js +0 -0
  45. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-D3TWcJOI.js +0 -0
  46. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-DRNcaZ-V.js +0 -0
  47. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/assets/worker-MF2p-l5_.js +0 -0
  48. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/images/favicon.png +0 -0
  49. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/images/header-logo.svg +0 -0
  50. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/images/sign-in-logo.svg +0 -0
  51. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/index.html +0 -0
  52. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/static/index.min.css +0 -0
  53. {fastadmin-0.4.9 → fastadmin-0.6.0}/fastadmin/templates/index.html +0 -0
@@ -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
+ ![FastAdmin demo — admin panel for FastAPI, Flask and Django](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/demo.gif)
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
+ ![FastAdmin demo — admin panel for FastAPI, Flask and Django](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/demo.gif)
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(settings.ADMIN_SESSION_ID_KEY, value=session_id, httponly=True)
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(settings.ADMIN_SESSION_ID_KEY, value=session_id, httponly=True)
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, # type: ignore [arg-type]
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": str(exc)},
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(settings.ADMIN_SESSION_ID_KEY, value=session_id, httponly=True)
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"]) # type: ignore [type-var]
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"]) # type: ignore [type-var]
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
- if not id:
88
- return False
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: