fastadmin 0.2.22__tar.gz → 0.3.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.2.22 → fastadmin-0.3.0}/PKG-INFO +63 -45
- {fastadmin-0.2.22 → fastadmin-0.3.0}/README.md +54 -37
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/exceptions.py +2 -2
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/app/api.py +27 -19
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/fastapi/api.py +19 -8
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/flask/api.py +28 -20
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/helpers.py +45 -8
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/schemas.py +1 -1
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/service.py +34 -15
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/base.py +29 -9
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/decorators.py +7 -4
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/django.py +8 -8
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/ponyorm.py +15 -7
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/sqlalchemy.py +28 -15
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/tortoise.py +2 -2
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/schemas.py +1 -1
- {fastadmin-0.2.22 → fastadmin-0.3.0}/pyproject.toml +7 -6
- {fastadmin-0.2.22 → fastadmin-0.3.0}/LICENSE +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/app/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/app/urls.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/app/views.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/fastapi/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/fastapi/app.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/fastapi/views.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/flask/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/flask/app.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/flask/views.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/helpers.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/__init__.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/settings.py +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-6Z7niv9l.js +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-C151k0-L.js +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-D1fCgYB7.js +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-D3TWcJOI.js +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-DRNcaZ-V.js +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-MF2p-l5_.js +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/images/favicon.png +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/images/header-logo.svg +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/images/sign-in-logo.svg +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/index.html +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/index.min.css +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/index.min.js +0 -0
- {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/templates/index.html +0 -0
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
2
|
Name: fastadmin
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.0
|
|
4
4
|
Summary: FastAdmin is an easy-to-use Admin Dashboard App for FastAPI/Flask/Django inspired by Django Admin.
|
|
5
5
|
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
6
7
|
Keywords: fastapi,admin
|
|
7
8
|
Author: Seva D
|
|
8
9
|
Author-email: vsdudakov@gmail.com
|
|
9
|
-
Requires-Python: >=3.
|
|
10
|
+
Requires-Python: >=3.12,<4.0
|
|
10
11
|
Classifier: Environment :: Console
|
|
11
12
|
Classifier: Framework :: Django
|
|
12
13
|
Classifier: Framework :: FastAPI
|
|
@@ -14,10 +15,9 @@ Classifier: Framework :: Flask
|
|
|
14
15
|
Classifier: License :: OSI Approved :: MIT License
|
|
15
16
|
Classifier: Operating System :: OS Independent
|
|
16
17
|
Classifier: Programming Language :: Python :: 3
|
|
17
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
-
Classifier: Programming Language :: Python :: 3.11
|
|
19
18
|
Classifier: Programming Language :: Python :: 3.12
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
21
21
|
Classifier: Topic :: Software Development :: Documentation
|
|
22
22
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
23
|
Classifier: Topic :: Software Development :: Widget Sets
|
|
@@ -27,32 +27,32 @@ Provides-Extra: flask
|
|
|
27
27
|
Provides-Extra: pony
|
|
28
28
|
Provides-Extra: sqlalchemy
|
|
29
29
|
Provides-Extra: tortoise-orm
|
|
30
|
-
Requires-Dist: asgiref (>=3.
|
|
31
|
-
Requires-Dist: django (==
|
|
30
|
+
Requires-Dist: asgiref (>=3.11.1,<4.0.0)
|
|
31
|
+
Requires-Dist: django (==6.*) ; extra == "django"
|
|
32
32
|
Requires-Dist: fastapi (==0.*) ; extra == "fastapi"
|
|
33
33
|
Requires-Dist: flask (==3.*) ; extra == "flask"
|
|
34
|
+
Requires-Dist: greenlet (>=3.0,<4.0) ; extra == "sqlalchemy"
|
|
34
35
|
Requires-Dist: pony (==0.*) ; extra == "pony"
|
|
35
36
|
Requires-Dist: pyjwt (>=2.6.0,<3.0.0)
|
|
36
37
|
Requires-Dist: sqlalchemy[asyncio] (==2.*) ; extra == "sqlalchemy"
|
|
37
|
-
Requires-Dist: tortoise-orm (==
|
|
38
|
+
Requires-Dist: tortoise-orm (==1.*) ; extra == "tortoise-orm"
|
|
38
39
|
Project-URL: Homepage, https://github.com/vsdudakov/fastadmin
|
|
39
40
|
Project-URL: Repository, https://github.com/vsdudakov/fastadmin
|
|
40
41
|
Description-Content-Type: text/markdown
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
# Admin Dashboard for FastAPI / Flask / Django
|
|
43
44
|
|
|
44
45
|
[](https://codecov.io/gh/vsdudakov/fastadmin)
|
|
45
46
|
[](https://github.com/vsdudakov/fastadmin/blob/master/LICENSE)
|
|
46
47
|
[](https://pypi.org/project/fastadmin/)
|
|
47
|
-
[](https://www.python.org/downloads/release/python-3100/)
|
|
48
|
-
[](https://www.python.org/downloads/release/python-3110/)
|
|
49
48
|
[](https://www.python.org/downloads/release/python-3120/)
|
|
49
|
+
[](https://www.python.org/downloads/release/python-3130/)
|
|
50
50
|
|
|
51
51
|
## Screenshots
|
|
52
52
|
|
|
53
|
-

|
|
54
|
+

|
|
55
|
+

|
|
56
56
|
|
|
57
57
|
<p align="center">
|
|
58
58
|
<a href="https://twitter.com/intent/tweet?text=Admin%20Dashboard%20For%20FastAPI&url=https://github.com/vsdudakov/fastadmin&hashtags=FastAPI,AdminDashboard">
|
|
@@ -65,7 +65,7 @@ Description-Content-Type: text/markdown
|
|
|
65
65
|
## Introduction
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
<a href='https://github.com/vsdudakov/fastadmin' target='_blank'>FastAdmin</a> is an easy-to-use
|
|
68
|
+
<a href='https://github.com/vsdudakov/fastadmin' target='_blank'>FastAdmin</a> is an easy-to-use admin dashboard for FastAPI, Django, and Flask, inspired by Django Admin.
|
|
69
69
|
|
|
70
70
|
|
|
71
71
|
|
|
@@ -81,7 +81,7 @@ Description-Content-Type: text/markdown
|
|
|
81
81
|
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
FastAdmin
|
|
84
|
+
FastAdmin is built with relationships in mind and admiration for Django Admin. Its design focuses on making it as easy as possible to configure your admin dashboard for FastAPI, Django, or Flask.
|
|
85
85
|
|
|
86
86
|
|
|
87
87
|
|
|
@@ -97,7 +97,7 @@ FastAdmin was built with relations in mind and admiration for the excellent and
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
|
|
100
|
-
FastAdmin
|
|
100
|
+
FastAdmin aims to be minimal, functional, and familiar.
|
|
101
101
|
|
|
102
102
|
|
|
103
103
|
|
|
@@ -123,7 +123,7 @@ FastAdmin is designed to be minimalistic, functional and yet familiar.
|
|
|
123
123
|
|
|
124
124
|
|
|
125
125
|
|
|
126
|
-
If you have
|
|
126
|
+
If you have questions beyond this documentation, feel free to <a href='mailto:vsdudakov@gmail.com' target='_blank'>email us</a>.
|
|
127
127
|
|
|
128
128
|
|
|
129
129
|
|
|
@@ -141,7 +141,7 @@ If you have any questions that are beyond the scope of the documentation, Please
|
|
|
141
141
|
|
|
142
142
|
|
|
143
143
|
|
|
144
|
-
Follow the steps below to
|
|
144
|
+
Follow the steps below to set up FastAdmin:
|
|
145
145
|
|
|
146
146
|
|
|
147
147
|
|
|
@@ -155,7 +155,7 @@ Follow the steps below to setup FastAdmin:
|
|
|
155
155
|
|
|
156
156
|
|
|
157
157
|
|
|
158
|
-
Install the package
|
|
158
|
+
Install the package with pip:
|
|
159
159
|
|
|
160
160
|
|
|
161
161
|
|
|
@@ -175,7 +175,7 @@ Install the package using pip:
|
|
|
175
175
|
|
|
176
176
|
|
|
177
177
|
|
|
178
|
-
|
|
178
|
+
On zsh and macOS, use quotes: <code>pip install 'fastadmin[fastapi,django]'</code>
|
|
179
179
|
|
|
180
180
|
|
|
181
181
|
|
|
@@ -197,13 +197,13 @@ Note: For zsh and macos use: <code>pip install fastadmin[fastapi,django]</code>
|
|
|
197
197
|
|
|
198
198
|
```bash
|
|
199
199
|
|
|
200
|
-
pip install fastadmin[fastapi,django]
|
|
201
|
-
pip install fastadmin[fastapi,tortoise-orm] #
|
|
202
|
-
pip install fastadmin[fastapi,pony]
|
|
203
|
-
pip install fastadmin[fastapi,sqlalchemy]
|
|
204
|
-
pip install fastadmin[django]
|
|
205
|
-
pip install fastadmin[django,pony]
|
|
206
|
-
pip install fastadmin[flask,sqlalchemy]
|
|
200
|
+
pip install fastadmin[fastapi,django] # FastAPI with Django ORM
|
|
201
|
+
pip install fastadmin[fastapi,tortoise-orm] # FastAPI with Tortoise ORM
|
|
202
|
+
pip install fastadmin[fastapi,pony] # FastAPI with Pony ORM
|
|
203
|
+
pip install fastadmin[fastapi,sqlalchemy] # FastAPI with SQLAlchemy (includes greenlet)
|
|
204
|
+
pip install fastadmin[django] # Django with Django ORM
|
|
205
|
+
pip install fastadmin[django,pony] # Django with Pony ORM
|
|
206
|
+
pip install fastadmin[flask,sqlalchemy] # Flask with SQLAlchemy (includes greenlet)
|
|
207
207
|
|
|
208
208
|
```
|
|
209
209
|
|
|
@@ -213,7 +213,7 @@ pip install fastadmin[flask,sqlalchemy] # for flask with sqlalchemy
|
|
|
213
213
|
|
|
214
214
|
|
|
215
215
|
|
|
216
|
-
|
|
216
|
+
Or install with Poetry:
|
|
217
217
|
|
|
218
218
|
|
|
219
219
|
|
|
@@ -239,13 +239,13 @@ Install the package using poetry:
|
|
|
239
239
|
|
|
240
240
|
```bash
|
|
241
241
|
|
|
242
|
-
poetry add 'fastadmin[fastapi,django]'
|
|
243
|
-
poetry add 'fastadmin[fastapi,tortoise-orm]'
|
|
244
|
-
poetry add 'fastadmin[fastapi,pony]'
|
|
245
|
-
poetry add 'fastadmin[fastapi,sqlalchemy]'
|
|
246
|
-
poetry add 'fastadmin[django]'
|
|
247
|
-
poetry add 'fastadmin[django,pony]'
|
|
248
|
-
poetry add 'fastadmin[flask,sqlalchemy]'
|
|
242
|
+
poetry add 'fastadmin[fastapi,django]'
|
|
243
|
+
poetry add 'fastadmin[fastapi,tortoise-orm]'
|
|
244
|
+
poetry add 'fastadmin[fastapi,pony]'
|
|
245
|
+
poetry add 'fastadmin[fastapi,sqlalchemy]'
|
|
246
|
+
poetry add 'fastadmin[django]'
|
|
247
|
+
poetry add 'fastadmin[django,pony]'
|
|
248
|
+
poetry add 'fastadmin[flask,sqlalchemy]'
|
|
249
249
|
|
|
250
250
|
```
|
|
251
251
|
|
|
@@ -255,11 +255,11 @@ poetry add 'fastadmin[flask,sqlalchemy]' # for flask with sqlalchemy
|
|
|
255
255
|
|
|
256
256
|
|
|
257
257
|
|
|
258
|
-
Configure required settings using virtual environment variables:
|
|
259
258
|
|
|
260
259
|
|
|
261
260
|
|
|
262
261
|
|
|
262
|
+
When using SQLAlchemy, the <code>greenlet</code> package is required (included in the <code>fastadmin[sqlalchemy]</code> extra).
|
|
263
263
|
|
|
264
264
|
|
|
265
265
|
|
|
@@ -271,11 +271,27 @@ Configure required settings using virtual environment variables:
|
|
|
271
271
|
|
|
272
272
|
|
|
273
273
|
|
|
274
|
+
Configure the required settings with environment variables:
|
|
274
275
|
|
|
275
276
|
|
|
276
277
|
|
|
277
278
|
|
|
278
|
-
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
|
|
294
|
+
You can add these variables to a <code>.env</code> file and load them with python-dotenv. See <a href='https://vsdudakov.github.io/fastadmin#settings'>all settings</a> in the full documentation.
|
|
279
295
|
|
|
280
296
|
|
|
281
297
|
|
|
@@ -314,7 +330,7 @@ export ADMIN_SECRET_KEY=secret_key
|
|
|
314
330
|
|
|
315
331
|
|
|
316
332
|
|
|
317
|
-
|
|
333
|
+
Set up FastAdmin for your framework
|
|
318
334
|
|
|
319
335
|
|
|
320
336
|
|
|
@@ -517,14 +533,14 @@ class UserAdmin(TortoiseModelAdmin):
|
|
|
517
533
|
}
|
|
518
534
|
|
|
519
535
|
async def authenticate(self, username: str, password: str) -> int | None:
|
|
520
|
-
user = await self.model_cls.filter(
|
|
536
|
+
user = await self.model_cls.filter(username=username, is_superuser=True).first()
|
|
521
537
|
if not user:
|
|
522
538
|
return None
|
|
523
539
|
if not bcrypt.checkpw(password.encode(), user.hash_password.encode()):
|
|
524
540
|
return None
|
|
525
541
|
return user.id
|
|
526
542
|
|
|
527
|
-
async def change_password(self, id: UUID | int, password: str) -> None:
|
|
543
|
+
async def change_password(self, id: UUID | int | str, password: str) -> None:
|
|
528
544
|
user = await self.model_cls.filter(id=id).first()
|
|
529
545
|
if not user:
|
|
530
546
|
return
|
|
@@ -595,7 +611,7 @@ class UserAdmin(DjangoModelAdmin):
|
|
|
595
611
|
|
|
596
612
|
|
|
597
613
|
|
|
598
|
-
###
|
|
614
|
+
### SQLAlchemy
|
|
599
615
|
|
|
600
616
|
|
|
601
617
|
|
|
@@ -664,7 +680,7 @@ class UserAdmin(SqlAlchemyModelAdmin):
|
|
|
664
680
|
return None
|
|
665
681
|
return obj.id
|
|
666
682
|
|
|
667
|
-
async def change_password(self, id: uuid.UUID | int, password: str) -> None:
|
|
683
|
+
async def change_password(self, id: uuid.UUID | int | str, password: str) -> None:
|
|
668
684
|
sessionmaker = self.get_sessionmaker()
|
|
669
685
|
async with sessionmaker() as session:
|
|
670
686
|
hash_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
|
|
@@ -785,7 +801,9 @@ class UserAdmin(PonyORMModelAdmin):
|
|
|
785
801
|
|
|
786
802
|
|
|
787
803
|
## Documentation
|
|
788
|
-
|
|
804
|
+
|
|
805
|
+
Full documentation is available at [vsdudakov.github.io/fastadmin](https://vsdudakov.github.io/fastadmin).
|
|
789
806
|
|
|
790
807
|
## License
|
|
791
|
-
|
|
808
|
+
|
|
809
|
+
This project is licensed under the MIT License — see the [LICENSE](https://github.com/vsdudakov/fastadmin/blob/main/LICENSE) file for details.
|
|
@@ -1,17 +1,16 @@
|
|
|
1
|
-
|
|
1
|
+
# Admin Dashboard for FastAPI / Flask / Django
|
|
2
2
|
|
|
3
3
|
[](https://codecov.io/gh/vsdudakov/fastadmin)
|
|
4
4
|
[](https://github.com/vsdudakov/fastadmin/blob/master/LICENSE)
|
|
5
5
|
[](https://pypi.org/project/fastadmin/)
|
|
6
|
-
[](https://www.python.org/downloads/release/python-3100/)
|
|
7
|
-
[](https://www.python.org/downloads/release/python-3110/)
|
|
8
6
|
[](https://www.python.org/downloads/release/python-3120/)
|
|
7
|
+
[](https://www.python.org/downloads/release/python-3130/)
|
|
9
8
|
|
|
10
9
|
## Screenshots
|
|
11
10
|
|
|
12
|
-

|
|
12
|
+

|
|
13
|
+

|
|
15
14
|
|
|
16
15
|
<p align="center">
|
|
17
16
|
<a href="https://twitter.com/intent/tweet?text=Admin%20Dashboard%20For%20FastAPI&url=https://github.com/vsdudakov/fastadmin&hashtags=FastAPI,AdminDashboard">
|
|
@@ -24,7 +23,7 @@
|
|
|
24
23
|
## Introduction
|
|
25
24
|
|
|
26
25
|
|
|
27
|
-
<a href='https://github.com/vsdudakov/fastadmin' target='_blank'>FastAdmin</a> is an easy-to-use
|
|
26
|
+
<a href='https://github.com/vsdudakov/fastadmin' target='_blank'>FastAdmin</a> is an easy-to-use admin dashboard for FastAPI, Django, and Flask, inspired by Django Admin.
|
|
28
27
|
|
|
29
28
|
|
|
30
29
|
|
|
@@ -40,7 +39,7 @@
|
|
|
40
39
|
|
|
41
40
|
|
|
42
41
|
|
|
43
|
-
FastAdmin
|
|
42
|
+
FastAdmin is built with relationships in mind and admiration for Django Admin. Its design focuses on making it as easy as possible to configure your admin dashboard for FastAPI, Django, or Flask.
|
|
44
43
|
|
|
45
44
|
|
|
46
45
|
|
|
@@ -56,7 +55,7 @@ FastAdmin was built with relations in mind and admiration for the excellent and
|
|
|
56
55
|
|
|
57
56
|
|
|
58
57
|
|
|
59
|
-
FastAdmin
|
|
58
|
+
FastAdmin aims to be minimal, functional, and familiar.
|
|
60
59
|
|
|
61
60
|
|
|
62
61
|
|
|
@@ -82,7 +81,7 @@ FastAdmin is designed to be minimalistic, functional and yet familiar.
|
|
|
82
81
|
|
|
83
82
|
|
|
84
83
|
|
|
85
|
-
If you have
|
|
84
|
+
If you have questions beyond this documentation, feel free to <a href='mailto:vsdudakov@gmail.com' target='_blank'>email us</a>.
|
|
86
85
|
|
|
87
86
|
|
|
88
87
|
|
|
@@ -100,7 +99,7 @@ If you have any questions that are beyond the scope of the documentation, Please
|
|
|
100
99
|
|
|
101
100
|
|
|
102
101
|
|
|
103
|
-
Follow the steps below to
|
|
102
|
+
Follow the steps below to set up FastAdmin:
|
|
104
103
|
|
|
105
104
|
|
|
106
105
|
|
|
@@ -114,7 +113,7 @@ Follow the steps below to setup FastAdmin:
|
|
|
114
113
|
|
|
115
114
|
|
|
116
115
|
|
|
117
|
-
Install the package
|
|
116
|
+
Install the package with pip:
|
|
118
117
|
|
|
119
118
|
|
|
120
119
|
|
|
@@ -134,7 +133,7 @@ Install the package using pip:
|
|
|
134
133
|
|
|
135
134
|
|
|
136
135
|
|
|
137
|
-
|
|
136
|
+
On zsh and macOS, use quotes: <code>pip install 'fastadmin[fastapi,django]'</code>
|
|
138
137
|
|
|
139
138
|
|
|
140
139
|
|
|
@@ -156,13 +155,13 @@ Note: For zsh and macos use: <code>pip install fastadmin[fastapi,django]</code>
|
|
|
156
155
|
|
|
157
156
|
```bash
|
|
158
157
|
|
|
159
|
-
pip install fastadmin[fastapi,django]
|
|
160
|
-
pip install fastadmin[fastapi,tortoise-orm] #
|
|
161
|
-
pip install fastadmin[fastapi,pony]
|
|
162
|
-
pip install fastadmin[fastapi,sqlalchemy]
|
|
163
|
-
pip install fastadmin[django]
|
|
164
|
-
pip install fastadmin[django,pony]
|
|
165
|
-
pip install fastadmin[flask,sqlalchemy]
|
|
158
|
+
pip install fastadmin[fastapi,django] # FastAPI with Django ORM
|
|
159
|
+
pip install fastadmin[fastapi,tortoise-orm] # FastAPI with Tortoise ORM
|
|
160
|
+
pip install fastadmin[fastapi,pony] # FastAPI with Pony ORM
|
|
161
|
+
pip install fastadmin[fastapi,sqlalchemy] # FastAPI with SQLAlchemy (includes greenlet)
|
|
162
|
+
pip install fastadmin[django] # Django with Django ORM
|
|
163
|
+
pip install fastadmin[django,pony] # Django with Pony ORM
|
|
164
|
+
pip install fastadmin[flask,sqlalchemy] # Flask with SQLAlchemy (includes greenlet)
|
|
166
165
|
|
|
167
166
|
```
|
|
168
167
|
|
|
@@ -172,7 +171,7 @@ pip install fastadmin[flask,sqlalchemy] # for flask with sqlalchemy
|
|
|
172
171
|
|
|
173
172
|
|
|
174
173
|
|
|
175
|
-
|
|
174
|
+
Or install with Poetry:
|
|
176
175
|
|
|
177
176
|
|
|
178
177
|
|
|
@@ -198,13 +197,13 @@ Install the package using poetry:
|
|
|
198
197
|
|
|
199
198
|
```bash
|
|
200
199
|
|
|
201
|
-
poetry add 'fastadmin[fastapi,django]'
|
|
202
|
-
poetry add 'fastadmin[fastapi,tortoise-orm]'
|
|
203
|
-
poetry add 'fastadmin[fastapi,pony]'
|
|
204
|
-
poetry add 'fastadmin[fastapi,sqlalchemy]'
|
|
205
|
-
poetry add 'fastadmin[django]'
|
|
206
|
-
poetry add 'fastadmin[django,pony]'
|
|
207
|
-
poetry add 'fastadmin[flask,sqlalchemy]'
|
|
200
|
+
poetry add 'fastadmin[fastapi,django]'
|
|
201
|
+
poetry add 'fastadmin[fastapi,tortoise-orm]'
|
|
202
|
+
poetry add 'fastadmin[fastapi,pony]'
|
|
203
|
+
poetry add 'fastadmin[fastapi,sqlalchemy]'
|
|
204
|
+
poetry add 'fastadmin[django]'
|
|
205
|
+
poetry add 'fastadmin[django,pony]'
|
|
206
|
+
poetry add 'fastadmin[flask,sqlalchemy]'
|
|
208
207
|
|
|
209
208
|
```
|
|
210
209
|
|
|
@@ -214,11 +213,11 @@ poetry add 'fastadmin[flask,sqlalchemy]' # for flask with sqlalchemy
|
|
|
214
213
|
|
|
215
214
|
|
|
216
215
|
|
|
217
|
-
Configure required settings using virtual environment variables:
|
|
218
216
|
|
|
219
217
|
|
|
220
218
|
|
|
221
219
|
|
|
220
|
+
When using SQLAlchemy, the <code>greenlet</code> package is required (included in the <code>fastadmin[sqlalchemy]</code> extra).
|
|
222
221
|
|
|
223
222
|
|
|
224
223
|
|
|
@@ -230,11 +229,27 @@ Configure required settings using virtual environment variables:
|
|
|
230
229
|
|
|
231
230
|
|
|
232
231
|
|
|
232
|
+
Configure the required settings with environment variables:
|
|
233
233
|
|
|
234
234
|
|
|
235
235
|
|
|
236
236
|
|
|
237
|
-
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
You can add these variables to a <code>.env</code> file and load them with python-dotenv. See <a href='https://vsdudakov.github.io/fastadmin#settings'>all settings</a> in the full documentation.
|
|
238
253
|
|
|
239
254
|
|
|
240
255
|
|
|
@@ -273,7 +288,7 @@ export ADMIN_SECRET_KEY=secret_key
|
|
|
273
288
|
|
|
274
289
|
|
|
275
290
|
|
|
276
|
-
|
|
291
|
+
Set up FastAdmin for your framework
|
|
277
292
|
|
|
278
293
|
|
|
279
294
|
|
|
@@ -476,14 +491,14 @@ class UserAdmin(TortoiseModelAdmin):
|
|
|
476
491
|
}
|
|
477
492
|
|
|
478
493
|
async def authenticate(self, username: str, password: str) -> int | None:
|
|
479
|
-
user = await self.model_cls.filter(
|
|
494
|
+
user = await self.model_cls.filter(username=username, is_superuser=True).first()
|
|
480
495
|
if not user:
|
|
481
496
|
return None
|
|
482
497
|
if not bcrypt.checkpw(password.encode(), user.hash_password.encode()):
|
|
483
498
|
return None
|
|
484
499
|
return user.id
|
|
485
500
|
|
|
486
|
-
async def change_password(self, id: UUID | int, password: str) -> None:
|
|
501
|
+
async def change_password(self, id: UUID | int | str, password: str) -> None:
|
|
487
502
|
user = await self.model_cls.filter(id=id).first()
|
|
488
503
|
if not user:
|
|
489
504
|
return
|
|
@@ -554,7 +569,7 @@ class UserAdmin(DjangoModelAdmin):
|
|
|
554
569
|
|
|
555
570
|
|
|
556
571
|
|
|
557
|
-
###
|
|
572
|
+
### SQLAlchemy
|
|
558
573
|
|
|
559
574
|
|
|
560
575
|
|
|
@@ -623,7 +638,7 @@ class UserAdmin(SqlAlchemyModelAdmin):
|
|
|
623
638
|
return None
|
|
624
639
|
return obj.id
|
|
625
640
|
|
|
626
|
-
async def change_password(self, id: uuid.UUID | int, password: str) -> None:
|
|
641
|
+
async def change_password(self, id: uuid.UUID | int | str, password: str) -> None:
|
|
627
642
|
sessionmaker = self.get_sessionmaker()
|
|
628
643
|
async with sessionmaker() as session:
|
|
629
644
|
hash_password = bcrypt.hashpw(password.encode(), bcrypt.gensalt()).decode()
|
|
@@ -744,7 +759,9 @@ class UserAdmin(PonyORMModelAdmin):
|
|
|
744
759
|
|
|
745
760
|
|
|
746
761
|
## Documentation
|
|
747
|
-
|
|
762
|
+
|
|
763
|
+
Full documentation is available at [vsdudakov.github.io/fastadmin](https://vsdudakov.github.io/fastadmin).
|
|
748
764
|
|
|
749
765
|
## License
|
|
750
|
-
|
|
766
|
+
|
|
767
|
+
This project is licensed under the MIT License — see the [LICENSE](https://github.com/vsdudakov/fastadmin/blob/main/LICENSE) file for details.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
class AdminApiException(Exception):
|
|
2
|
-
|
|
3
|
-
detail: str | None
|
|
2
|
+
"""API exception with HTTP status code and detail message."""
|
|
4
3
|
|
|
5
4
|
def __init__(self, status_code: int, detail: str | None = None):
|
|
5
|
+
super().__init__(detail or "")
|
|
6
6
|
self.status_code = status_code
|
|
7
7
|
self.detail = detail
|
|
@@ -12,7 +12,7 @@ from django.http import StreamingHttpResponse
|
|
|
12
12
|
from django.http.request import HttpRequest
|
|
13
13
|
|
|
14
14
|
from fastadmin.api.exceptions import AdminApiException
|
|
15
|
-
from fastadmin.api.helpers import is_valid_id
|
|
15
|
+
from fastadmin.api.helpers import is_valid_id, parse_list_filters_from_query_params
|
|
16
16
|
from fastadmin.api.schemas import ActionInputSchema, ExportInputSchema, SignInInputSchema
|
|
17
17
|
from fastadmin.api.service import ApiService, get_user_id_from_session_id
|
|
18
18
|
from fastadmin.settings import settings
|
|
@@ -164,18 +164,22 @@ async def list_objs(request: HttpRequest, model: str) -> JsonResponse:
|
|
|
164
164
|
if request.method != "GET":
|
|
165
165
|
return JsonResponse({"error": "Method not allowed"}, status=405)
|
|
166
166
|
try:
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
167
|
+
search = request.GET.get("search") or None
|
|
168
|
+
sort_by = request.GET.get("sort_by") or None
|
|
169
|
+
offset = int(request.GET.get("offset", 0))
|
|
170
|
+
limit = int(request.GET.get("limit", 10))
|
|
171
|
+
list_filters = parse_list_filters_from_query_params(
|
|
172
|
+
request.GET.keys,
|
|
173
|
+
request.GET.getlist,
|
|
174
|
+
exclude={"search", "sort_by", "offset", "limit"},
|
|
175
|
+
)
|
|
172
176
|
|
|
173
177
|
objs, total = await api_service.list(
|
|
174
178
|
request.COOKIES.get(settings.ADMIN_SESSION_ID_KEY, None),
|
|
175
179
|
model,
|
|
176
180
|
search=search,
|
|
177
181
|
sort_by=sort_by,
|
|
178
|
-
filters=
|
|
182
|
+
filters=list_filters,
|
|
179
183
|
offset=offset,
|
|
180
184
|
limit=limit,
|
|
181
185
|
)
|
|
@@ -192,7 +196,7 @@ async def list_objs(request: HttpRequest, model: str) -> JsonResponse:
|
|
|
192
196
|
|
|
193
197
|
|
|
194
198
|
@csrf_exempt
|
|
195
|
-
async def get(request: HttpRequest, model: str, id: UUID | int) -> JsonResponse:
|
|
199
|
+
async def get(request: HttpRequest, model: str, id: UUID | int | str) -> JsonResponse:
|
|
196
200
|
"""This method is used to get an object.
|
|
197
201
|
|
|
198
202
|
:params model: a name of model.
|
|
@@ -202,7 +206,7 @@ async def get(request: HttpRequest, model: str, id: UUID | int) -> JsonResponse:
|
|
|
202
206
|
if request.method != "GET":
|
|
203
207
|
return JsonResponse({"error": "Method not allowed"}, status=405)
|
|
204
208
|
if not is_valid_id(id):
|
|
205
|
-
return JsonResponse({"error": "Invalid id. It must be a UUID or
|
|
209
|
+
return JsonResponse({"error": "Invalid id. It must be a UUID, an integer, or a non-empty string."}, status=422)
|
|
206
210
|
try:
|
|
207
211
|
obj = await api_service.get(
|
|
208
212
|
request.COOKIES.get(settings.ADMIN_SESSION_ID_KEY, None),
|
|
@@ -237,7 +241,7 @@ async def add(request: HttpRequest, model: str) -> JsonResponse:
|
|
|
237
241
|
|
|
238
242
|
|
|
239
243
|
@csrf_exempt
|
|
240
|
-
async def change_password(request: HttpRequest, id: UUID | int) -> JsonResponse:
|
|
244
|
+
async def change_password(request: HttpRequest, id: UUID | int | str) -> JsonResponse:
|
|
241
245
|
"""This method is used to change a password.
|
|
242
246
|
|
|
243
247
|
:params id: an id of object.
|
|
@@ -247,7 +251,7 @@ async def change_password(request: HttpRequest, id: UUID | int) -> JsonResponse:
|
|
|
247
251
|
if request.method != "PATCH":
|
|
248
252
|
return JsonResponse({"error": "Method not allowed"}, status=405)
|
|
249
253
|
if not is_valid_id(id):
|
|
250
|
-
return JsonResponse({"error": "Invalid id. It must be a UUID or
|
|
254
|
+
return JsonResponse({"error": "Invalid id. It must be a UUID, an integer, or a non-empty string."}, status=422)
|
|
251
255
|
try:
|
|
252
256
|
await api_service.change_password(
|
|
253
257
|
request.COOKIES.get(settings.ADMIN_SESSION_ID_KEY, None),
|
|
@@ -261,7 +265,7 @@ async def change_password(request: HttpRequest, id: UUID | int) -> JsonResponse:
|
|
|
261
265
|
|
|
262
266
|
|
|
263
267
|
@csrf_exempt
|
|
264
|
-
async def change(request: HttpRequest, model: str, id: UUID | int) -> JsonResponse:
|
|
268
|
+
async def change(request: HttpRequest, model: str, id: UUID | int | str) -> JsonResponse:
|
|
265
269
|
"""This method is used to change an object.
|
|
266
270
|
|
|
267
271
|
:params model: a name of model.
|
|
@@ -272,7 +276,7 @@ async def change(request: HttpRequest, model: str, id: UUID | int) -> JsonRespon
|
|
|
272
276
|
if request.method != "PATCH":
|
|
273
277
|
return JsonResponse({"error": "Method not allowed"}, status=405)
|
|
274
278
|
if not is_valid_id(id):
|
|
275
|
-
return JsonResponse({"error": "Invalid id. It must be a UUID or
|
|
279
|
+
return JsonResponse({"error": "Invalid id. It must be a UUID, an integer, or a non-empty string."}, status=422)
|
|
276
280
|
try:
|
|
277
281
|
obj = await api_service.change(
|
|
278
282
|
request.COOKIES.get(settings.ADMIN_SESSION_ID_KEY, None),
|
|
@@ -299,9 +303,13 @@ async def export(request: HttpRequest, model: str) -> JsonResponse:
|
|
|
299
303
|
"""
|
|
300
304
|
if request.method != "POST":
|
|
301
305
|
return JsonResponse({"error": "Method not allowed"}, status=405)
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
306
|
+
search = request.GET.get("search") or None
|
|
307
|
+
sort_by = request.GET.get("sort_by") or None
|
|
308
|
+
list_filters = parse_list_filters_from_query_params(
|
|
309
|
+
request.GET.keys,
|
|
310
|
+
request.GET.getlist,
|
|
311
|
+
exclude={"search", "sort_by", "offset", "limit"},
|
|
312
|
+
)
|
|
305
313
|
try:
|
|
306
314
|
payload = ExportInputSchema(**json.loads(request.body))
|
|
307
315
|
file_name, content_type, stream = await api_service.export(
|
|
@@ -310,7 +318,7 @@ async def export(request: HttpRequest, model: str) -> JsonResponse:
|
|
|
310
318
|
payload,
|
|
311
319
|
search=search,
|
|
312
320
|
sort_by=sort_by,
|
|
313
|
-
filters=
|
|
321
|
+
filters=list_filters,
|
|
314
322
|
)
|
|
315
323
|
response = StreamingHttpResponse(stream, content_type=content_type)
|
|
316
324
|
response.headers["Content-Disposition"] = f'attachment; filename="{file_name}"'
|
|
@@ -324,7 +332,7 @@ async def export(request: HttpRequest, model: str) -> JsonResponse:
|
|
|
324
332
|
async def delete(
|
|
325
333
|
request: HttpRequest,
|
|
326
334
|
model: str,
|
|
327
|
-
id: UUID | int,
|
|
335
|
+
id: UUID | int | str,
|
|
328
336
|
) -> JsonResponse:
|
|
329
337
|
"""This method is used to delete an object.
|
|
330
338
|
|
|
@@ -335,7 +343,7 @@ async def delete(
|
|
|
335
343
|
if request.method != "DELETE":
|
|
336
344
|
return JsonResponse({"error": "Method not allowed"}, status=405)
|
|
337
345
|
if not is_valid_id(id):
|
|
338
|
-
return JsonResponse({"error": "Invalid id. It must be a UUID or
|
|
346
|
+
return JsonResponse({"error": "Invalid id. It must be a UUID, an integer, or a non-empty string."}, status=422)
|
|
339
347
|
try:
|
|
340
348
|
deleted_id = await api_service.delete(
|
|
341
349
|
request.COOKIES.get(settings.ADMIN_SESSION_ID_KEY, None),
|