Skip to content

Commit c6c27d5

Browse files
committed
Fixed bugs, added doc strings and tests for frontend
1 parent 09f7858 commit c6c27d5

34 files changed

Lines changed: 857 additions & 302 deletions

File tree

docs/images/change.png

-18.5 KB
Loading

docs/images/list.png

-2.28 KB
Loading

docs/images/signin.png

-14.1 KB
Loading

fastadmin/api/api.py

Lines changed: 98 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from fastapi.responses import Response, StreamingResponse
77

88
from fastadmin.api.depends import get_user_id, get_user_id_or_none
9+
from fastadmin.api.helpers import sanitize
910
from fastadmin.models.base import BaseModelAdmin
1011
from fastadmin.models.helpers import get_admin_model, get_admin_models
1112
from fastadmin.schemas.api import ExportSchema, SignInInputSchema
@@ -29,6 +30,12 @@ async def sign_in(
2930
response: Response,
3031
payload: SignInInputSchema,
3132
):
33+
"""This method is used to sign in.
34+
35+
:params response: a response object.
36+
:params payload: a payload object.
37+
:return: None.
38+
"""
3239
model = settings.ADMIN_USER_MODEL
3340
admin_model = get_admin_model(model)
3441
if not admin_model:
@@ -57,6 +64,11 @@ async def sign_out(
5764
response: Response,
5865
_: str = Depends(get_user_id),
5966
):
67+
"""This method is used to sign out.
68+
69+
:params response: a response object.
70+
:return: None.
71+
"""
6072
response.delete_cookie(settings.ADMIN_SESSION_ID_KEY)
6173
return None
6274

@@ -65,6 +77,11 @@ async def sign_out(
6577
async def me(
6678
user_id: str = Depends(get_user_id),
6779
):
80+
"""This method is used to get current user.
81+
82+
:params user_id: a user id.
83+
:return: A user object.
84+
"""
6885
model = settings.ADMIN_USER_MODEL
6986
admin_model = get_admin_model(model)
7087
if not admin_model:
@@ -85,11 +102,25 @@ async def list(
85102
limit: int | None = 10,
86103
_: str = Depends(get_user_id),
87104
):
105+
"""This method is used to get a list of objects.
106+
107+
:params request: a request object.
108+
:params model: a name of model.
109+
:params search: a search string.
110+
:params sort_by: a sort by string.
111+
:params offset: an offset.
112+
:params limit: a limit.
113+
:return: A list of objects.
114+
"""
88115
admin_model = get_admin_model(model)
89116
if not admin_model:
90117
raise HTTPException(status.HTTP_404_NOT_FOUND, detail=f"{model} model is not registered.")
91118

92-
filters = {k: v for k, v in request.query_params._dict.items() if k not in ("search", "sort_by", "offset", "limit")}
119+
filters = {
120+
k: sanitize(v)
121+
for k, v in request.query_params._dict.items()
122+
if k not in ("search", "sort_by", "offset", "limit")
123+
}
93124
objs, total = await admin_model.get_list(
94125
offset=offset,
95126
limit=limit,
@@ -109,6 +140,12 @@ async def get(
109140
id: str,
110141
_: str = Depends(get_user_id),
111142
):
143+
"""This method is used to get an object.
144+
145+
:params model: a name of model.
146+
:params id: an id of object.
147+
:return: An object.
148+
"""
112149
admin_model = get_admin_model(model)
113150
if not admin_model:
114151
raise HTTPException(status.HTTP_404_NOT_FOUND, detail=f"{model} model is not registered.")
@@ -124,6 +161,12 @@ async def add(
124161
payload: dict,
125162
_: str = Depends(get_user_id),
126163
):
164+
"""This method is used to add an object.
165+
166+
:params model: a name of model.
167+
:params payload: a payload object.
168+
:return: An object.
169+
"""
127170
admin_model = get_admin_model(model)
128171
if not admin_model:
129172
raise HTTPException(status.HTTP_404_NOT_FOUND, detail=f"{model} model is not registered.")
@@ -139,6 +182,13 @@ async def change(
139182
payload: dict,
140183
_: str = Depends(get_user_id),
141184
):
185+
"""This method is used to change an object.
186+
187+
:params model: a name of model.
188+
:params id: an id of object.
189+
:params payload: a payload object.
190+
:return: An object.
191+
"""
142192
admin_model = get_admin_model(model)
143193
if not admin_model:
144194
raise HTTPException(status.HTTP_404_NOT_FOUND, detail=f"{model} model is not registered.")
@@ -158,6 +208,15 @@ async def export(
158208
sort_by: str = "-created_at",
159209
_: str = Depends(get_user_id),
160210
):
211+
"""This method is used to export a list of objects.
212+
213+
:params request: a request object.
214+
:params model: a name of model.
215+
:params payload: a payload object.
216+
:params search: a search string.
217+
:params sort_by: a sort by string.
218+
:return: A list of objects.
219+
"""
161220
admin_model = get_admin_model(model)
162221
if not admin_model:
163222
raise HTTPException(status.HTTP_404_NOT_FOUND, detail=f"{model} model is not registered.")
@@ -186,6 +245,12 @@ async def delete(
186245
id: str,
187246
user_id: str = Depends(get_user_id),
188247
):
248+
"""This method is used to delete an object.
249+
250+
:params model: a name of model.
251+
:params id: an id of object.
252+
:return: An object.
253+
"""
189254
admin_model = get_admin_model(model)
190255
if not admin_model:
191256
raise HTTPException(status.HTTP_404_NOT_FOUND, detail=f"{model} model is not registered.")
@@ -202,6 +267,11 @@ async def delete(
202267
async def configuration(
203268
user_id: str | None = Depends(get_user_id_or_none),
204269
):
270+
"""This method is used to get a configuration.
271+
272+
:params user_id: an id of user.
273+
:return: A configuration.
274+
"""
205275
if not user_id:
206276
return ConfigurationSchema(
207277
site_name=settings.ADMIN_SITE_NAME,
@@ -210,6 +280,8 @@ async def configuration(
210280
site_favicon=settings.ADMIN_SITE_FAVICON,
211281
primary_color=settings.ADMIN_PRIMARY_COLOR,
212282
username_field=settings.ADMIN_USER_MODEL_USERNAME_FIELD,
283+
date_format=settings.ADMIN_DATE_FORMAT,
284+
datetime_format=settings.ADMIN_DATETIME_FORMAT,
213285
models=[],
214286
)
215287

@@ -218,46 +290,49 @@ async def configuration(
218290
for model_cls in models:
219291
admin_obj: BaseModelAdmin = models[model_cls](model_cls)
220292

221-
fields = admin_obj.get_fields()
293+
model_fields = admin_obj.get_model_fields()
294+
222295
fields_schema = []
223-
for field_name in fields:
296+
for field_name, field in model_fields.items():
224297
list_display = admin_obj.get_list_display()
298+
column_index = list_display.index(field_name) if field_name in list_display else None
225299
list_configuration = None
226300
filter_widget_type = None
227301
filter_widget_props = None
228-
if field_name in list_display:
302+
if column_index is not None:
229303
if field_name in admin_obj.list_filter:
230304
filter_widget_type, filter_widget_props = admin_obj.get_filter_widget(field_name)
231305
sorter = True
232306
if admin_obj.sortable_by and field_name not in admin_obj.sortable_by:
233307
sorter = False
234308
list_configuration = ListConfigurationFieldSchema(
309+
index=column_index,
235310
sorter=sorter,
236311
is_link=field_name in admin_obj.list_display_links,
237312
empty_value_display=admin_obj.empty_value_display,
238313
filter_widget_type=filter_widget_type,
239314
filter_widget_props=filter_widget_props,
240315
)
241316

242-
form_hidden_fields = admin_obj.get_form_hidden_fields()
243-
244317
add_configuration = None
245-
if field_name not in form_hidden_fields:
246-
form_widget_type, form_widget_props = admin_obj.get_form_widget(field_name)
247-
add_configuration = AddConfigurationFieldSchema(
248-
form_widget_type=form_widget_type,
249-
form_widget_props=form_widget_props,
250-
required=form_widget_props.get("required", False),
251-
)
252-
253318
change_configuration = None
254-
if field_name not in form_hidden_fields:
255-
form_widget_type, form_widget_props = admin_obj.get_form_widget(field_name)
256-
change_configuration = ChangeConfigurationFieldSchema(
257-
form_widget_type=form_widget_type,
258-
form_widget_props=form_widget_props,
259-
required=form_widget_props.get("required", False),
260-
)
319+
if not field.get("form_hidden"):
320+
fields = admin_obj.get_fields()
321+
form_index = fields.index(field_name) if field_name in fields else None
322+
if form_index is not None:
323+
form_widget_type, form_widget_props = admin_obj.get_form_widget(field_name)
324+
add_configuration = AddConfigurationFieldSchema(
325+
index=form_index,
326+
form_widget_type=form_widget_type,
327+
form_widget_props=form_widget_props,
328+
required=form_widget_props.get("required", False),
329+
)
330+
change_configuration = ChangeConfigurationFieldSchema(
331+
index=form_index,
332+
form_widget_type=form_widget_type,
333+
form_widget_props=form_widget_props,
334+
required=form_widget_props.get("required", False),
335+
)
261336

262337
fields_schema.append(
263338
ModelFieldSchema(
@@ -303,5 +378,7 @@ async def configuration(
303378
site_favicon=settings.ADMIN_SITE_FAVICON,
304379
primary_color=settings.ADMIN_PRIMARY_COLOR,
305380
username_field=settings.ADMIN_USER_MODEL_USERNAME_FIELD,
381+
date_format=settings.ADMIN_DATE_FORMAT,
382+
datetime_format=settings.ADMIN_DATETIME_FORMAT,
306383
models=models_schemas,
307384
)

fastadmin/api/depends.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@
99

1010

1111
async def get_user_id_or_none(request: Request) -> str | None:
12+
"""This method is used to get user id from request or None.
13+
14+
:params request: a request object.
15+
:return: A user id or None.
16+
"""
1217
admin_model = get_admin_model(settings.ADMIN_USER_MODEL)
1318
if not admin_model:
1419
return None
@@ -38,6 +43,11 @@ async def get_user_id_or_none(request: Request) -> str | None:
3843

3944

4045
async def get_user_id(request: Request) -> str:
46+
"""This method is used to get user id from request.
47+
48+
:params request: a request object.
49+
:return: A user id.
50+
"""
4151
user_id = await get_user_id_or_none(request)
4252
if not user_id:
4353
raise HTTPException(status.HTTP_401_UNAUTHORIZED)

fastadmin/api/helpers.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
def sanitize(value: str) -> bool | None | str:
2+
"""Sanitize value
3+
4+
:params value: a value.
5+
:return: A sanitized value.
6+
"""
7+
if value == "false":
8+
return False
9+
elif value == "true":
10+
return True
11+
elif value == "null":
12+
return None
13+
return value

0 commit comments

Comments
 (0)