sqladmin 0.19.0__tar.gz → 0.20.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 (54) hide show
  1. {sqladmin-0.19.0 → sqladmin-0.20.0}/PKG-INFO +1 -1
  2. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/__init__.py +1 -1
  3. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/application.py +9 -10
  4. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/models.py +37 -4
  5. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/pagination.py +4 -0
  6. {sqladmin-0.19.0 → sqladmin-0.20.0}/.gitignore +0 -0
  7. {sqladmin-0.19.0 → sqladmin-0.20.0}/LICENSE.md +0 -0
  8. {sqladmin-0.19.0 → sqladmin-0.20.0}/README.md +0 -0
  9. {sqladmin-0.19.0 → sqladmin-0.20.0}/pyproject.toml +0 -0
  10. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/_menu.py +0 -0
  11. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/_queries.py +0 -0
  12. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/_types.py +0 -0
  13. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/_validators.py +0 -0
  14. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/ajax.py +0 -0
  15. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/authentication.py +0 -0
  16. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/exceptions.py +0 -0
  17. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/fields.py +0 -0
  18. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/formatters.py +0 -0
  19. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/forms.py +0 -0
  20. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/helpers.py +0 -0
  21. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/py.typed +0 -0
  22. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/css/flatpickr.min.css +0 -0
  23. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/css/fontawesome.min.css +0 -0
  24. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/css/main.css +0 -0
  25. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/css/select2.min.css +0 -0
  26. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/css/tabler-icons.min.css +0 -0
  27. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/css/tabler-icons.min.css.map +0 -0
  28. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/css/tabler.min.css +0 -0
  29. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/js/bootstrap.min.js +0 -0
  30. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/js/flatpickr.min.js +0 -0
  31. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/js/jquery.min.js +0 -0
  32. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/js/main.js +0 -0
  33. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/js/popper.min.js +0 -0
  34. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/js/select2.full.min.js +0 -0
  35. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/js/tabler.min.js +0 -0
  36. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/webfonts/fa-brands-400.woff2 +0 -0
  37. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/webfonts/fa-regular-400.woff2 +0 -0
  38. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/webfonts/fa-solid-900.woff2 +0 -0
  39. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/statics/webfonts/tabler-icons.woff2 +0 -0
  40. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/_macros.html +0 -0
  41. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/base.html +0 -0
  42. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/create.html +0 -0
  43. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/details.html +0 -0
  44. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/edit.html +0 -0
  45. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/error.html +0 -0
  46. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/index.html +0 -0
  47. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/layout.html +0 -0
  48. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/list.html +0 -0
  49. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/login.html +0 -0
  50. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/modals/delete.html +0 -0
  51. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/modals/details_action_confirmation.html +0 -0
  52. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templates/sqladmin/modals/list_action_confirmation.html +0 -0
  53. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/templating.py +0 -0
  54. {sqladmin-0.19.0 → sqladmin-0.20.0}/sqladmin/widgets.py +0 -0
@@ -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,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",
@@ -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,
@@ -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
@@ -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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes