fastadmin 0.1.15__tar.gz → 0.1.17__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.1.15 → fastadmin-0.1.17}/PKG-INFO +11 -110
- {fastadmin-0.1.15 → fastadmin-0.1.17}/README.md +10 -109
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/api/api.py +3 -5
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/models/base.py +13 -10
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/models/orm/tortoise.py +1 -1
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/schemas/configuration.py +1 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/js/main.min.js +3 -3
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/js/main.min.js.map +1 -1
- {fastadmin-0.1.15 → fastadmin-0.1.17}/pyproject.toml +1 -1
- {fastadmin-0.1.15 → fastadmin-0.1.17}/LICENSE +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/__init__.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/api/__init__.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/api/depends.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/api/helpers.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/app.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/models/__init__.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/models/decorators.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/models/helpers.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/models/orm/__init__.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/schemas/__init__.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/schemas/api.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/settings.py +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/css/main.min.css +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/css/main.min.css.map +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/images/favicon.png +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/images/header-logo.svg +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/images/sign-in-logo.svg +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/js/787.cda612ba.chunk.js +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/static/js/787.cda612ba.chunk.js.map +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/templates/index.html +0 -0
- {fastadmin-0.1.15 → fastadmin-0.1.17}/fastadmin/views.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: fastadmin
|
3
|
-
Version: 0.1.
|
3
|
+
Version: 0.1.17
|
4
4
|
Summary:
|
5
5
|
Home-page: https://github.com/vsdudakov/fastadmin
|
6
6
|
License: MIT
|
@@ -39,6 +39,12 @@ Description-Content-Type: text/markdown
|
|
39
39
|

|
40
40
|

|
41
41
|
|
42
|
+
<p align="center">
|
43
|
+
<a href="https://twitter.com/intent/tweet?text=Admin%20Dashboard%20For%20FastAPI&url=https://github.com/vsdudakov/fastadmin&hashtags=FastAPI,AdminDashboard">
|
44
|
+
<img alt="tweet" src="https://img.shields.io/twitter/url/https/twitter?label=Share%20on%20twitter&style=social" target="_blank" />
|
45
|
+
</a>
|
46
|
+
</p>
|
47
|
+
|
42
48
|
## Introduction
|
43
49
|
|
44
50
|
FastAdmin is an easy-to-use Admin App for FastAPI inspired by Django Admin.
|
@@ -158,122 +164,17 @@ class GroupAdmin(TortoiseModelAdmin):
|
|
158
164
|
|
159
165
|
#### Run your project
|
160
166
|
|
161
|
-
Run your project (see https://fastapi.tiangolo.com/tutorial/first-steps/):
|
167
|
+
Run your project (see [https://fastapi.tiangolo.com/tutorial/first-steps/](https://fastapi.tiangolo.com/tutorial/first-steps/)):
|
162
168
|
|
163
169
|
```bash
|
164
170
|
uvicorn ...
|
165
171
|
```
|
166
172
|
|
167
|
-
Go to http://localhost:8000/admin
|
168
|
-
|
169
|
-
## Configuration
|
170
|
-
|
171
|
-
You can find all env variables to configure FastAdmin [here](https://github.com/vsdudakov/fastadmin/blob/main/fastadmin/settings.py)
|
172
|
-
|
173
|
-
You can find all parameters and methods to configure your ModelAdmin classes [here](https://github.com/vsdudakov/fastadmin/blob/main/fastadmin/models/base.py)
|
174
|
-
|
175
|
-
Example:
|
176
|
-
|
177
|
-
```python
|
178
|
-
from fastadmin import TortoiseModelAdmin, register, action, display
|
179
|
-
|
180
|
-
@register(User)
|
181
|
-
class UserAdmin(TortoiseModelAdmin):
|
182
|
-
label_fields = ("email", "id")
|
183
|
-
exclude = ("hash_password",)
|
184
|
-
list_display = ("id", "email", "has_hash_password", "is_superuser", "is_active")
|
185
|
-
list_display_links = ("id",)
|
186
|
-
list_filter = ("id", "email", "is_superuser")
|
187
|
-
search_fields = ("email",)
|
188
|
-
actions = ("set_as_active",)
|
173
|
+
Go to [http://localhost:8000/admin](http://localhost:8000/admin).
|
189
174
|
|
190
|
-
|
191
|
-
return False
|
175
|
+
## Documentation
|
192
176
|
|
193
|
-
|
194
|
-
async def set_as_active(self, ids: list[int | UUID]) -> None:
|
195
|
-
await User.filter(id__in=ids).update(is_active=True)
|
196
|
-
|
197
|
-
@display
|
198
|
-
async def has_hash_password(self, obj: Any) -> Any:
|
199
|
-
return obj.hash_password is not None
|
200
|
-
|
201
|
-
...
|
202
|
-
```
|
203
|
-
|
204
|
-
## Other ORMs or own implementation
|
205
|
-
|
206
|
-
We are going to support SQLAlchemy and Pony ORM soon...
|
207
|
-
|
208
|
-
If you have smth else (your own implementation of ORM and so on) you will may overload ModelAdmin class and implement the following interfaces
|
209
|
-
|
210
|
-
```python
|
211
|
-
from typing import Any
|
212
|
-
from collections import OrderedDict
|
213
|
-
from fastadmin import ModelAdmin, WidgetType
|
214
|
-
|
215
|
-
class MyModelAdmin(ModelAdmin):
|
216
|
-
async def save_model(self, id: UUID | int | None, payload: dict) -> dict | None:
|
217
|
-
"""This method is used to save orm/db model object.
|
218
|
-
|
219
|
-
:params id: an id of object.
|
220
|
-
:params payload: a payload from request.
|
221
|
-
:return: A saved object or None.
|
222
|
-
"""
|
223
|
-
raise NotImplementedError
|
224
|
-
|
225
|
-
async def delete_model(self, id: UUID | int) -> None:
|
226
|
-
"""This method is used to delete orm/db model object.
|
227
|
-
|
228
|
-
:params id: an id of object.
|
229
|
-
:return: None.
|
230
|
-
"""
|
231
|
-
raise NotImplementedError
|
232
|
-
|
233
|
-
async def get_obj(self, id: UUID | int) -> dict | None:
|
234
|
-
"""This method is used to get orm/db model object by id.
|
235
|
-
|
236
|
-
:params id: an id of object.
|
237
|
-
:return: An object or None.
|
238
|
-
"""
|
239
|
-
raise NotImplementedError
|
240
|
-
|
241
|
-
async def get_list(
|
242
|
-
self,
|
243
|
-
offset: int | None = None,
|
244
|
-
limit: int | None = None,
|
245
|
-
search: str | None = None,
|
246
|
-
sort_by: str | None = None,
|
247
|
-
filters: dict | None = None,
|
248
|
-
) -> tuple[list[dict], int]:
|
249
|
-
"""This method is used to get list of orm/db model objects.
|
250
|
-
|
251
|
-
:params offset: an offset for pagination.
|
252
|
-
:params limit: a limit for pagination.
|
253
|
-
:params search: a search query.
|
254
|
-
:params sort_by: a sort by field name.
|
255
|
-
:params filters: a dict of filters.
|
256
|
-
:return: A tuple of list of objects and total count.
|
257
|
-
"""
|
258
|
-
raise NotImplementedError
|
259
|
-
|
260
|
-
def get_model_fields(self) -> OrderedDict[str, dict]:
|
261
|
-
"""This method is used to get all orm/db model fields
|
262
|
-
with saving ordering (non relations, fk, o2o, m2m).
|
263
|
-
|
264
|
-
:return: An OrderedDict of model fields.
|
265
|
-
"""
|
266
|
-
raise NotImplementedError
|
267
|
-
|
268
|
-
def get_form_widget(self, field_name: str) -> tuple[WidgetType, dict]:
|
269
|
-
"""This method is used to get form item widget
|
270
|
-
for field from orm/db model.
|
271
|
-
|
272
|
-
:params field_name: a model field name.
|
273
|
-
:return: A tuple of widget type and widget props.
|
274
|
-
"""
|
275
|
-
raise NotImplementedError
|
276
|
-
```
|
177
|
+
See full documentation [here](https://vsdudakov.github.io/fastadmin/).
|
277
178
|
|
278
179
|
## License
|
279
180
|
|
@@ -12,6 +12,12 @@
|
|
12
12
|

|
13
13
|

|
14
14
|
|
15
|
+
<p align="center">
|
16
|
+
<a href="https://twitter.com/intent/tweet?text=Admin%20Dashboard%20For%20FastAPI&url=https://github.com/vsdudakov/fastadmin&hashtags=FastAPI,AdminDashboard">
|
17
|
+
<img alt="tweet" src="https://img.shields.io/twitter/url/https/twitter?label=Share%20on%20twitter&style=social" target="_blank" />
|
18
|
+
</a>
|
19
|
+
</p>
|
20
|
+
|
15
21
|
## Introduction
|
16
22
|
|
17
23
|
FastAdmin is an easy-to-use Admin App for FastAPI inspired by Django Admin.
|
@@ -131,122 +137,17 @@ class GroupAdmin(TortoiseModelAdmin):
|
|
131
137
|
|
132
138
|
#### Run your project
|
133
139
|
|
134
|
-
Run your project (see https://fastapi.tiangolo.com/tutorial/first-steps/):
|
140
|
+
Run your project (see [https://fastapi.tiangolo.com/tutorial/first-steps/](https://fastapi.tiangolo.com/tutorial/first-steps/)):
|
135
141
|
|
136
142
|
```bash
|
137
143
|
uvicorn ...
|
138
144
|
```
|
139
145
|
|
140
|
-
Go to http://localhost:8000/admin
|
141
|
-
|
142
|
-
## Configuration
|
143
|
-
|
144
|
-
You can find all env variables to configure FastAdmin [here](https://github.com/vsdudakov/fastadmin/blob/main/fastadmin/settings.py)
|
145
|
-
|
146
|
-
You can find all parameters and methods to configure your ModelAdmin classes [here](https://github.com/vsdudakov/fastadmin/blob/main/fastadmin/models/base.py)
|
147
|
-
|
148
|
-
Example:
|
149
|
-
|
150
|
-
```python
|
151
|
-
from fastadmin import TortoiseModelAdmin, register, action, display
|
152
|
-
|
153
|
-
@register(User)
|
154
|
-
class UserAdmin(TortoiseModelAdmin):
|
155
|
-
label_fields = ("email", "id")
|
156
|
-
exclude = ("hash_password",)
|
157
|
-
list_display = ("id", "email", "has_hash_password", "is_superuser", "is_active")
|
158
|
-
list_display_links = ("id",)
|
159
|
-
list_filter = ("id", "email", "is_superuser")
|
160
|
-
search_fields = ("email",)
|
161
|
-
actions = ("set_as_active",)
|
146
|
+
Go to [http://localhost:8000/admin](http://localhost:8000/admin).
|
162
147
|
|
163
|
-
|
164
|
-
return False
|
148
|
+
## Documentation
|
165
149
|
|
166
|
-
|
167
|
-
async def set_as_active(self, ids: list[int | UUID]) -> None:
|
168
|
-
await User.filter(id__in=ids).update(is_active=True)
|
169
|
-
|
170
|
-
@display
|
171
|
-
async def has_hash_password(self, obj: Any) -> Any:
|
172
|
-
return obj.hash_password is not None
|
173
|
-
|
174
|
-
...
|
175
|
-
```
|
176
|
-
|
177
|
-
## Other ORMs or own implementation
|
178
|
-
|
179
|
-
We are going to support SQLAlchemy and Pony ORM soon...
|
180
|
-
|
181
|
-
If you have smth else (your own implementation of ORM and so on) you will may overload ModelAdmin class and implement the following interfaces
|
182
|
-
|
183
|
-
```python
|
184
|
-
from typing import Any
|
185
|
-
from collections import OrderedDict
|
186
|
-
from fastadmin import ModelAdmin, WidgetType
|
187
|
-
|
188
|
-
class MyModelAdmin(ModelAdmin):
|
189
|
-
async def save_model(self, id: UUID | int | None, payload: dict) -> dict | None:
|
190
|
-
"""This method is used to save orm/db model object.
|
191
|
-
|
192
|
-
:params id: an id of object.
|
193
|
-
:params payload: a payload from request.
|
194
|
-
:return: A saved object or None.
|
195
|
-
"""
|
196
|
-
raise NotImplementedError
|
197
|
-
|
198
|
-
async def delete_model(self, id: UUID | int) -> None:
|
199
|
-
"""This method is used to delete orm/db model object.
|
200
|
-
|
201
|
-
:params id: an id of object.
|
202
|
-
:return: None.
|
203
|
-
"""
|
204
|
-
raise NotImplementedError
|
205
|
-
|
206
|
-
async def get_obj(self, id: UUID | int) -> dict | None:
|
207
|
-
"""This method is used to get orm/db model object by id.
|
208
|
-
|
209
|
-
:params id: an id of object.
|
210
|
-
:return: An object or None.
|
211
|
-
"""
|
212
|
-
raise NotImplementedError
|
213
|
-
|
214
|
-
async def get_list(
|
215
|
-
self,
|
216
|
-
offset: int | None = None,
|
217
|
-
limit: int | None = None,
|
218
|
-
search: str | None = None,
|
219
|
-
sort_by: str | None = None,
|
220
|
-
filters: dict | None = None,
|
221
|
-
) -> tuple[list[dict], int]:
|
222
|
-
"""This method is used to get list of orm/db model objects.
|
223
|
-
|
224
|
-
:params offset: an offset for pagination.
|
225
|
-
:params limit: a limit for pagination.
|
226
|
-
:params search: a search query.
|
227
|
-
:params sort_by: a sort by field name.
|
228
|
-
:params filters: a dict of filters.
|
229
|
-
:return: A tuple of list of objects and total count.
|
230
|
-
"""
|
231
|
-
raise NotImplementedError
|
232
|
-
|
233
|
-
def get_model_fields(self) -> OrderedDict[str, dict]:
|
234
|
-
"""This method is used to get all orm/db model fields
|
235
|
-
with saving ordering (non relations, fk, o2o, m2m).
|
236
|
-
|
237
|
-
:return: An OrderedDict of model fields.
|
238
|
-
"""
|
239
|
-
raise NotImplementedError
|
240
|
-
|
241
|
-
def get_form_widget(self, field_name: str) -> tuple[WidgetType, dict]:
|
242
|
-
"""This method is used to get form item widget
|
243
|
-
for field from orm/db model.
|
244
|
-
|
245
|
-
:params field_name: a model field name.
|
246
|
-
:return: A tuple of widget type and widget props.
|
247
|
-
"""
|
248
|
-
raise NotImplementedError
|
249
|
-
```
|
150
|
+
See full documentation [here](https://vsdudakov.github.io/fastadmin/).
|
250
151
|
|
251
152
|
## License
|
252
153
|
|
@@ -370,7 +370,7 @@ async def configuration(
|
|
370
370
|
),
|
371
371
|
)
|
372
372
|
|
373
|
-
for field_name in admin_obj.list_display:
|
373
|
+
for column_index, field_name in enumerate(admin_obj.list_display):
|
374
374
|
display_field_function = getattr(admin_obj, field_name, None)
|
375
375
|
if (
|
376
376
|
not display_field_function
|
@@ -379,15 +379,12 @@ async def configuration(
|
|
379
379
|
):
|
380
380
|
continue
|
381
381
|
|
382
|
-
column_index = admin_obj.list_display.index(field_name) if field_name in admin_obj.list_display else None
|
383
|
-
if column_index is None:
|
384
|
-
continue
|
385
382
|
fields_schema.append(
|
386
383
|
ModelFieldSchema(
|
387
384
|
name=field_name,
|
388
385
|
list_configuration=ListConfigurationFieldSchema(
|
389
386
|
index=column_index,
|
390
|
-
sorter=
|
387
|
+
sorter=False,
|
391
388
|
is_link=field_name in admin_obj.list_display_links,
|
392
389
|
empty_value_display=admin_obj.empty_value_display,
|
393
390
|
filter_widget_type=None,
|
@@ -433,6 +430,7 @@ async def configuration(
|
|
433
430
|
actions_on_bottom=admin_obj.actions_on_bottom,
|
434
431
|
actions_selection_counter=admin_obj.actions_selection_counter,
|
435
432
|
fields=fields_schema,
|
433
|
+
fieldsets=admin_obj.fieldsets,
|
436
434
|
list_per_page=admin_obj.list_per_page,
|
437
435
|
save_on_top=admin_obj.save_on_top,
|
438
436
|
save_as=admin_obj.save_as,
|
@@ -420,18 +420,21 @@ class BaseModelAdmin:
|
|
420
420
|
|
421
421
|
:return: A list of model field names.
|
422
422
|
"""
|
423
|
-
fields = self.fields
|
424
423
|
model_fields = self.get_model_fields()
|
425
|
-
if not fields:
|
426
|
-
return [f for f in model_fields if not self.exclude or f not in self.exclude]
|
427
|
-
return [f for f in fields if f in model_fields]
|
428
424
|
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
425
|
+
fields = [f for f in model_fields if model_fields[f].get("is_pk")]
|
426
|
+
if not self.fields:
|
427
|
+
if self.fieldsets:
|
428
|
+
for item in self.fieldsets:
|
429
|
+
for field in item[1].get("fields") or []:
|
430
|
+
if field not in fields and field not in self.exclude:
|
431
|
+
fields.append(field)
|
432
|
+
else:
|
433
|
+
for field in model_fields:
|
434
|
+
if field not in fields and field not in self.exclude:
|
435
|
+
fields.append(field)
|
436
|
+
|
437
|
+
return fields
|
435
438
|
|
436
439
|
def has_add_permission(self) -> bool:
|
437
440
|
"""This method is used to check if user has permission to add new model instance.
|
@@ -247,7 +247,7 @@ class TortoiseModelAdmin(BaseModelAdmin):
|
|
247
247
|
widget_props = {
|
248
248
|
"required": field.get("required") or False,
|
249
249
|
"disabled": field_name in self.readonly_fields,
|
250
|
-
"
|
250
|
+
"readOnly": field_name in self.readonly_fields,
|
251
251
|
}
|
252
252
|
match field.get("orm_class_name"):
|
253
253
|
case "CharField":
|
@@ -92,6 +92,7 @@ class ModelSchema(BaseModel):
|
|
92
92
|
actions_on_bottom: bool | None
|
93
93
|
actions_selection_counter: bool | None
|
94
94
|
fields: Sequence[ModelFieldSchema]
|
95
|
+
fieldsets: Sequence[tuple[str | None, dict[str, Sequence[str]]]] | None
|
95
96
|
list_per_page: int | None
|
96
97
|
save_on_top: bool | None
|
97
98
|
save_as: bool | None
|