sqladmin 0.19.0__py3-none-any.whl → 0.20.0__py3-none-any.whl

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.
sqladmin/__init__.py CHANGED
@@ -1,7 +1,7 @@
1
1
  from sqladmin.application import Admin, action, expose
2
2
  from sqladmin.models import BaseView, ModelView
3
3
 
4
- __version__ = "0.19.0"
4
+ __version__ = "0.20.0"
5
5
 
6
6
  __all__ = [
7
7
  "Admin",
sqladmin/application.py CHANGED
@@ -442,12 +442,13 @@ class Admin(BaseAdminView):
442
442
  pagination = await model_view.list(request)
443
443
  pagination.add_pagination_urls(request.url)
444
444
 
445
- if (
446
- pagination.page * pagination.page_size
447
- > pagination.count + pagination.page_size
448
- ):
449
- raise HTTPException(
450
- status_code=400, detail="Invalid page or pageSize parameter"
445
+ request_page = model_view.validate_page_number(
446
+ request.query_params.get("page"), 1
447
+ )
448
+
449
+ if request_page > pagination.page:
450
+ return RedirectResponse(
451
+ request.url.include_query_params(page=pagination.page), status_code=302
451
452
  )
452
453
 
453
454
  context = {"model_view": model_view, "pagination": pagination}
@@ -510,8 +511,7 @@ class Admin(BaseAdminView):
510
511
  identity = request.path_params["identity"]
511
512
  model_view = self._find_model_view(identity)
512
513
 
513
- Form = await model_view.scaffold_form()
514
- model_view._validate_form_class(model_view._form_create_rules, Form)
514
+ Form = await model_view.scaffold_form(model_view._form_create_rules)
515
515
  form_data = await self._handle_form_data(request)
516
516
  form = Form(form_data)
517
517
 
@@ -561,8 +561,7 @@ class Admin(BaseAdminView):
561
561
  if not model:
562
562
  raise HTTPException(status_code=404)
563
563
 
564
- Form = await model_view.scaffold_form()
565
- model_view._validate_form_class(model_view._form_edit_rules, Form)
564
+ Form = await model_view.scaffold_form(model_view._form_edit_rules)
566
565
  context = {
567
566
  "obj": model,
568
567
  "model_view": model_view,
sqladmin/models.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import json
3
4
  import time
4
5
  import warnings
5
6
  from enum import Enum
@@ -454,7 +455,7 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
454
455
  ```
455
456
  """
456
457
 
457
- export_types: ClassVar[List[str]] = ["csv"]
458
+ export_types: ClassVar[List[str]] = ["csv", "json"]
458
459
  """A list of available export filetypes.
459
460
  Currently only `csv` is supported.
460
461
  """
@@ -1015,10 +1016,11 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
1015
1016
  By default do nothing.
1016
1017
  """
1017
1018
 
1018
- async def scaffold_form(self) -> Type[Form]:
1019
+ async def scaffold_form(self, rules: List[str] | None = None) -> Type[Form]:
1019
1020
  if self.form is not None:
1020
1021
  return self.form
1021
- return await get_model_form(
1022
+
1023
+ form = await get_model_form(
1022
1024
  model=self.model,
1023
1025
  session_maker=self.session_maker,
1024
1026
  only=self._form_prop_names,
@@ -1032,6 +1034,11 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
1032
1034
  form_converter=self.form_converter,
1033
1035
  )
1034
1036
 
1037
+ if rules:
1038
+ self._validate_form_class(rules, form)
1039
+
1040
+ return form
1041
+
1035
1042
  def search_placeholder(self) -> str:
1036
1043
  """Return search placeholder text.
1037
1044
 
@@ -1152,7 +1159,9 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
1152
1159
  ) -> StreamingResponse:
1153
1160
  if export_type == "csv":
1154
1161
  return await self._export_csv(data)
1155
- raise NotImplementedError("Only export_type='csv' is implemented.")
1162
+ elif export_type == "json":
1163
+ return await self._export_json(data)
1164
+ raise NotImplementedError("Only export_type='csv' or 'json' is implemented.")
1156
1165
 
1157
1166
  async def _export_csv(
1158
1167
  self,
@@ -1179,6 +1188,30 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
1179
1188
  headers={"Content-Disposition": f"attachment;filename={filename}"},
1180
1189
  )
1181
1190
 
1191
+ async def _export_json(
1192
+ self,
1193
+ data: List[Any],
1194
+ ) -> StreamingResponse:
1195
+ async def generate() -> AsyncGenerator[str, None]:
1196
+ yield "["
1197
+ separator = "," if len(data) > 1 else ""
1198
+
1199
+ for row in data:
1200
+ row_dict = {
1201
+ name: await self.get_prop_value(row, name)
1202
+ for name in self._export_prop_names
1203
+ }
1204
+ yield json.dumps(row_dict) + separator
1205
+
1206
+ yield "]"
1207
+
1208
+ filename = secure_filename(self.get_export_name(export_type="json"))
1209
+ return StreamingResponse(
1210
+ content=generate(),
1211
+ media_type="application/json",
1212
+ headers={"Content-Disposition": f"attachment;filename={filename}"},
1213
+ )
1214
+
1182
1215
  def _refresh_form_rules_cache(self) -> None:
1183
1216
  if self.form_rules:
1184
1217
  self._form_create_rules = self.form_rules
sqladmin/pagination.py CHANGED
@@ -46,6 +46,10 @@ class Pagination:
46
46
 
47
47
  raise RuntimeError("Next page not found.")
48
48
 
49
+ def __post_init__(self) -> None:
50
+ # Clamp page
51
+ self.page = min(self.page, max(1, self.count // self.page_size + 1))
52
+
49
53
  def resize(self, page_size: int) -> Pagination:
50
54
  self.page = (self.page - 1) * self.page_size // page_size + 1
51
55
  self.page_size = page_size
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: sqladmin
3
- Version: 0.19.0
3
+ Version: 0.20.0
4
4
  Summary: SQLAlchemy admin for FastAPI and Starlette
5
5
  Project-URL: Documentation, https://aminalaee.dev/sqladmin
6
6
  Project-URL: Issues, https://github.com/aminalaee/sqladmin/issues
@@ -1,18 +1,18 @@
1
- sqladmin/__init__.py,sha256=SqLOSSEKfIFE3-zefHyyqKGrkbxCkfmL2aru-ptmEio,216
1
+ sqladmin/__init__.py,sha256=J9RDjM9xYLz2BbBMrYu0KfRxirw6tKr5hyr1xcoPi2g,216
2
2
  sqladmin/_menu.py,sha256=V6uKvIJGKrC0kmXq4M-DAgvPoHvgoGgKAw47OjsswGA,2609
3
3
  sqladmin/_queries.py,sha256=KqxMABvepoA0j-8Xizg6ASYS-sZDSdm5iFlU74vilQY,9697
4
4
  sqladmin/_types.py,sha256=3Zs0aPb14OS-9leahKxxzFopnIOiNftPZwdUmFDBKog,347
5
5
  sqladmin/_validators.py,sha256=w0siGhZQq4MD__lu9Edua9DgMOoKET_kk-alpARFHIM,1604
6
6
  sqladmin/ajax.py,sha256=wSP5P9cAIh3GImIc_-E_Mi14aJAcbtiy4_pDPukTs5E,2764
7
- sqladmin/application.py,sha256=DrG94Y9cTC5klNJ0XWfl5-FK3Wl1X7WKjVuH9QHCP0c,27416
7
+ sqladmin/application.py,sha256=7aMILrxNrDxGAM8WX32XxGQbDjGmy6gp0A-tQ1usqsM,27364
8
8
  sqladmin/authentication.py,sha256=QdN3rLZFU25ihaIIi7iisb55-oFi4GtV_k1xGFvnS6w,2482
9
9
  sqladmin/exceptions.py,sha256=6-E8m7rbWE3A7hNaSmB6CVqFzkEuwUpmU5AdGbouPCw,154
10
10
  sqladmin/fields.py,sha256=1CWoVSMr1WkhBJww0-rakx71gRATeIGA6dKgc26z99M,11660
11
11
  sqladmin/formatters.py,sha256=K06la0mm9-Bs5UA9L6KGJC_X_lV3UHdJ3ENI6j9j2Zg,480
12
12
  sqladmin/forms.py,sha256=5VhbRWbsG23eDAGz2c03HnED-titNkBdYzDr-TaBSi0,21541
13
13
  sqladmin/helpers.py,sha256=VTPOFbWkiC1My6MYYyVUCAdg7UmnViiYE2ZigiXx628,8615
14
- sqladmin/models.py,sha256=F6C9WZj3V7YO9tS1p1VhozsxTbjl5kygOLZbJ6yN-wE,39610
15
- sqladmin/pagination.py,sha256=vRXwCeuaUptovvY0wb1MDCIk8WBWwiE9X09SIkzSmcg,2464
14
+ sqladmin/models.py,sha256=7VFwuxz7oixl9jLD8QPLxlCErCUDdPWf3Ob60kOoF20,40630
15
+ sqladmin/pagination.py,sha256=zg_bAvqZd2Rf0wKJ7uiVfNV9vR0hrsilmi9Ak0SOG_U,2600
16
16
  sqladmin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
17
17
  sqladmin/templating.py,sha256=o-QMikTrOEgrneLonqCWR3SpAthr-9DoMwOmobM9zq0,2252
18
18
  sqladmin/widgets.py,sha256=xl9tGhj--KTRPmNhFn3WVbvN_tQfkYSNVBGicsFhrgM,3189
@@ -47,7 +47,7 @@ sqladmin/templates/sqladmin/login.html,sha256=Y_hlcIapfVFPNbSIbCe4Tbj5DLLD46emkS
47
47
  sqladmin/templates/sqladmin/modals/delete.html,sha256=jTuv6geT-AhK5HTgRmntrJ8CEi98-kwKrVDrzkOQWhw,1092
48
48
  sqladmin/templates/sqladmin/modals/details_action_confirmation.html,sha256=mN8LJ5OqypxNLAg2_GYZgQmGeK4E6t7JL5RmOEYuliM,1020
49
49
  sqladmin/templates/sqladmin/modals/list_action_confirmation.html,sha256=U52LLNmpLaMuUZSVtGK15oLXsEu6m2S3l9zj9sjN6uM,1078
50
- sqladmin-0.19.0.dist-info/METADATA,sha256=x__F5BuE9EUqAuEoyaqOQY28YbI9AFCwgYCTXvveRrg,5270
51
- sqladmin-0.19.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
52
- sqladmin-0.19.0.dist-info/licenses/LICENSE.md,sha256=4zzpHQMPtND4hzIgJA5qnb4R_wRBWJlYGqNrZolBeP8,1488
53
- sqladmin-0.19.0.dist-info/RECORD,,
50
+ sqladmin-0.20.0.dist-info/METADATA,sha256=YgbcA1NS7mKPEmMDPlMMOpkU7z3rcYMi-JLqOMe2hPM,5270
51
+ sqladmin-0.20.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
52
+ sqladmin-0.20.0.dist-info/licenses/LICENSE.md,sha256=4zzpHQMPtND4hzIgJA5qnb4R_wRBWJlYGqNrZolBeP8,1488
53
+ sqladmin-0.20.0.dist-info/RECORD,,