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.
Files changed (48) hide show
  1. {fastadmin-0.2.22 → fastadmin-0.3.0}/PKG-INFO +63 -45
  2. {fastadmin-0.2.22 → fastadmin-0.3.0}/README.md +54 -37
  3. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/exceptions.py +2 -2
  4. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/app/api.py +27 -19
  5. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/fastapi/api.py +19 -8
  6. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/flask/api.py +28 -20
  7. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/helpers.py +45 -8
  8. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/schemas.py +1 -1
  9. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/service.py +34 -15
  10. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/base.py +29 -9
  11. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/decorators.py +7 -4
  12. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/django.py +8 -8
  13. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/ponyorm.py +15 -7
  14. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/sqlalchemy.py +28 -15
  15. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/tortoise.py +2 -2
  16. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/schemas.py +1 -1
  17. {fastadmin-0.2.22 → fastadmin-0.3.0}/pyproject.toml +7 -6
  18. {fastadmin-0.2.22 → fastadmin-0.3.0}/LICENSE +0 -0
  19. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/__init__.py +0 -0
  20. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/__init__.py +0 -0
  21. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/__init__.py +0 -0
  22. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/__init__.py +0 -0
  23. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/app/__init__.py +0 -0
  24. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/app/urls.py +0 -0
  25. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/django/app/views.py +0 -0
  26. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/fastapi/__init__.py +0 -0
  27. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/fastapi/app.py +0 -0
  28. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/fastapi/views.py +0 -0
  29. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/flask/__init__.py +0 -0
  30. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/flask/app.py +0 -0
  31. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/api/frameworks/flask/views.py +0 -0
  32. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/__init__.py +0 -0
  33. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/helpers.py +0 -0
  34. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/models/orms/__init__.py +0 -0
  35. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/settings.py +0 -0
  36. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-6Z7niv9l.js +0 -0
  37. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-C151k0-L.js +0 -0
  38. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-D1fCgYB7.js +0 -0
  39. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-D3TWcJOI.js +0 -0
  40. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-DRNcaZ-V.js +0 -0
  41. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/assets/worker-MF2p-l5_.js +0 -0
  42. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/images/favicon.png +0 -0
  43. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/images/header-logo.svg +0 -0
  44. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/images/sign-in-logo.svg +0 -0
  45. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/index.html +0 -0
  46. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/index.min.css +0 -0
  47. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/static/index.min.js +0 -0
  48. {fastadmin-0.2.22 → fastadmin-0.3.0}/fastadmin/templates/index.html +0 -0
@@ -1,12 +1,13 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: fastadmin
3
- Version: 0.2.22
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,<4.0
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.7.0,<4.0.0)
31
- Requires-Dist: django (==5.*) ; extra == "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 (==0.*) ; extra == "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
- ## Admin Dashboard App for FastAPI/Flask/Django
43
+ # Admin Dashboard for FastAPI / Flask / Django
43
44
 
44
45
  [![codecov](https://codecov.io/gh/vsdudakov/fastadmin/branch/main/graph/badge.svg?token=RNGX5HOW3T)](https://codecov.io/gh/vsdudakov/fastadmin)
45
46
  [![License](https://img.shields.io/github/license/vsdudakov/fastadmin)](https://github.com/vsdudakov/fastadmin/blob/master/LICENSE)
46
47
  [![PyPi](https://badgen.net/pypi/v/fastadmin)](https://pypi.org/project/fastadmin/)
47
- [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/)
48
- [![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/)
49
48
  [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/)
49
+ [![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/)
50
50
 
51
51
  ## Screenshots
52
52
 
53
- ![SignIn View](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/signin.png)
54
- ![List View](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/list.png)
55
- ![Change View](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/change.png)
53
+ ![Sign-in view](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/signin.png)
54
+ ![List view](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/list.png)
55
+ ![Change view](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/change.png)
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 Admin Dashboard App for FastAPI/Django/Flask inspired by Django Admin.
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 was built with relations in mind and admiration for the excellent and popular Django Admin. It's engraved in its design that you may configure your admin dashboard for FastAPI/Django/Flask easiest way.
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 is designed to be minimalistic, functional and yet familiar.
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 any questions that are beyond the scope of the documentation, Please feel free to email <a href='mailto:vsdudakov@gmail.com' target='_blank'>us</a>.
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 setup FastAdmin:
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 using pip:
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
- Note: For zsh and macos use: <code>pip install fastadmin[fastapi,django]</code>
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] # for fastapi with django orm
201
- pip install fastadmin[fastapi,tortoise-orm] # for fastapi with tortoise orm
202
- pip install fastadmin[fastapi,pony] # for fastapi with pony orm
203
- pip install fastadmin[fastapi,sqlalchemy] # for fastapi with sqlalchemy orm
204
- pip install fastadmin[django] # for django with django orm
205
- pip install fastadmin[django,pony] # for django with pony orm
206
- pip install fastadmin[flask,sqlalchemy] # for flask with 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
- Install the package using poetry:
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]' # for fastapi with django orm
243
- poetry add 'fastadmin[fastapi,tortoise-orm]' # for fastapi with tortoise orm
244
- poetry add 'fastadmin[fastapi,pony]' # for fastapi with pony orm
245
- poetry add 'fastadmin[fastapi,sqlalchemy]' # for fastapi with sqlalchemy orm
246
- poetry add 'fastadmin[django]' # for django with django orm
247
- poetry add 'fastadmin[django,pony]' # for django with pony orm
248
- poetry add 'fastadmin[flask,sqlalchemy]' # for flask with 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
- Note: You can add these variables to .env and use python-dotenv to load them. See all settings <a href='https://vsdudakov.github.io/fastadmin#settings'>here</a>
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
- Setup FastAdmin for a framework
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(phone=username, is_superuser=True).first()
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
- ### SQL Alchemy
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
- See full documentation [here](https://vsdudakov.github.io/fastadmin).
804
+
805
+ Full documentation is available at [vsdudakov.github.io/fastadmin](https://vsdudakov.github.io/fastadmin).
789
806
 
790
807
  ## License
791
- This project is licensed under the MIT License - see the [LICENSE](https://github.com/vsdudakov/fastadmin/blob/main/LICENSE) file for details.
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
- ## Admin Dashboard App for FastAPI/Flask/Django
1
+ # Admin Dashboard for FastAPI / Flask / Django
2
2
 
3
3
  [![codecov](https://codecov.io/gh/vsdudakov/fastadmin/branch/main/graph/badge.svg?token=RNGX5HOW3T)](https://codecov.io/gh/vsdudakov/fastadmin)
4
4
  [![License](https://img.shields.io/github/license/vsdudakov/fastadmin)](https://github.com/vsdudakov/fastadmin/blob/master/LICENSE)
5
5
  [![PyPi](https://badgen.net/pypi/v/fastadmin)](https://pypi.org/project/fastadmin/)
6
- [![Python 3.10](https://img.shields.io/badge/python-3.10-blue.svg)](https://www.python.org/downloads/release/python-3100/)
7
- [![Python 3.11](https://img.shields.io/badge/python-3.11-blue.svg)](https://www.python.org/downloads/release/python-3110/)
8
6
  [![Python 3.12](https://img.shields.io/badge/python-3.12-blue.svg)](https://www.python.org/downloads/release/python-3120/)
7
+ [![Python 3.13](https://img.shields.io/badge/python-3.13-blue.svg)](https://www.python.org/downloads/release/python-3130/)
9
8
 
10
9
  ## Screenshots
11
10
 
12
- ![SignIn View](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/signin.png)
13
- ![List View](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/list.png)
14
- ![Change View](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/change.png)
11
+ ![Sign-in view](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/signin.png)
12
+ ![List view](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/list.png)
13
+ ![Change view](https://raw.githubusercontent.com/vsdudakov/fastadmin/main/docs/assets/images/change.png)
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 Admin Dashboard App for FastAPI/Django/Flask inspired by Django Admin.
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 was built with relations in mind and admiration for the excellent and popular Django Admin. It's engraved in its design that you may configure your admin dashboard for FastAPI/Django/Flask easiest way.
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 is designed to be minimalistic, functional and yet familiar.
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 any questions that are beyond the scope of the documentation, Please feel free to email <a href='mailto:vsdudakov@gmail.com' target='_blank'>us</a>.
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 setup FastAdmin:
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 using pip:
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
- Note: For zsh and macos use: <code>pip install fastadmin[fastapi,django]</code>
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] # for fastapi with django orm
160
- pip install fastadmin[fastapi,tortoise-orm] # for fastapi with tortoise orm
161
- pip install fastadmin[fastapi,pony] # for fastapi with pony orm
162
- pip install fastadmin[fastapi,sqlalchemy] # for fastapi with sqlalchemy orm
163
- pip install fastadmin[django] # for django with django orm
164
- pip install fastadmin[django,pony] # for django with pony orm
165
- pip install fastadmin[flask,sqlalchemy] # for flask with 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
- Install the package using poetry:
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]' # for fastapi with django orm
202
- poetry add 'fastadmin[fastapi,tortoise-orm]' # for fastapi with tortoise orm
203
- poetry add 'fastadmin[fastapi,pony]' # for fastapi with pony orm
204
- poetry add 'fastadmin[fastapi,sqlalchemy]' # for fastapi with sqlalchemy orm
205
- poetry add 'fastadmin[django]' # for django with django orm
206
- poetry add 'fastadmin[django,pony]' # for django with pony orm
207
- poetry add 'fastadmin[flask,sqlalchemy]' # for flask with 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
- Note: You can add these variables to .env and use python-dotenv to load them. See all settings <a href='https://vsdudakov.github.io/fastadmin#settings'>here</a>
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
- Setup FastAdmin for a framework
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(phone=username, is_superuser=True).first()
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
- ### SQL Alchemy
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
- See full documentation [here](https://vsdudakov.github.io/fastadmin).
762
+
763
+ Full documentation is available at [vsdudakov.github.io/fastadmin](https://vsdudakov.github.io/fastadmin).
748
764
 
749
765
  ## License
750
- This project is licensed under the MIT License - see the [LICENSE](https://github.com/vsdudakov/fastadmin/blob/main/LICENSE) file for details.
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
- status_code: int
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
- filters = request.GET.dict()
168
- search = filters.get("search", None)
169
- sort_by = filters.get("sort_by", None)
170
- offset = int(filters.get("offset", 0))
171
- limit = int(filters.get("limit", 10))
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=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 an integer."}, status=422)
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 an integer."}, status=422)
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 an integer."}, status=422)
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
- filters = request.GET.dict()
303
- search = filters.get("search", None)
304
- sort_by = filters.get("sort_by", None)
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=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 an integer."}, status=422)
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),