sqladmin 0.16.1__py3-none-any.whl → 0.17.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 +1 -1
- sqladmin/_queries.py +2 -2
- sqladmin/application.py +20 -8
- sqladmin/forms.py +1 -1
- sqladmin/helpers.py +5 -2
- sqladmin/models.py +40 -20
- sqladmin/templates/{create.html → sqladmin/create.html} +4 -1
- sqladmin/templates/{details.html → sqladmin/details.html} +3 -3
- sqladmin/templates/{edit.html → sqladmin/edit.html} +11 -6
- sqladmin/templates/{error.html → sqladmin/error.html} +1 -1
- sqladmin/templates/sqladmin/index.html +3 -0
- sqladmin/templates/{layout.html → sqladmin/layout.html} +2 -2
- sqladmin/templates/{list.html → sqladmin/list.html} +6 -6
- sqladmin/templates/{login.html → sqladmin/login.html} +1 -1
- sqladmin/widgets.py +20 -12
- {sqladmin-0.16.1.dist-info → sqladmin-0.17.0.dist-info}/METADATA +2 -2
- {sqladmin-0.16.1.dist-info → sqladmin-0.17.0.dist-info}/RECORD +24 -24
- {sqladmin-0.16.1.dist-info → sqladmin-0.17.0.dist-info}/WHEEL +1 -1
- sqladmin/templates/index.html +0 -3
- /sqladmin/templates/{_macros.html → sqladmin/_macros.html} +0 -0
- /sqladmin/templates/{base.html → sqladmin/base.html} +0 -0
- /sqladmin/templates/{modals → sqladmin/modals}/delete.html +0 -0
- /sqladmin/templates/{modals → sqladmin/modals}/details_action_confirmation.html +0 -0
- /sqladmin/templates/{modals → sqladmin/modals}/list_action_confirmation.html +0 -0
- {sqladmin-0.16.1.dist-info → sqladmin-0.17.0.dist-info}/licenses/LICENSE.md +0 -0
sqladmin/__init__.py
CHANGED
sqladmin/_queries.py
CHANGED
|
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING, Any, Dict, List
|
|
|
3
3
|
import anyio
|
|
4
4
|
from sqlalchemy import select
|
|
5
5
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
6
|
-
from sqlalchemy.orm import Session,
|
|
6
|
+
from sqlalchemy.orm import Session, selectinload
|
|
7
7
|
from sqlalchemy.sql.expression import Select, and_, or_
|
|
8
8
|
from starlette.requests import Request
|
|
9
9
|
|
|
@@ -152,7 +152,7 @@ class Query:
|
|
|
152
152
|
stmt = self.model_view._stmt_by_identifier(pk)
|
|
153
153
|
|
|
154
154
|
for relation in self.model_view._form_relations:
|
|
155
|
-
stmt = stmt.options(
|
|
155
|
+
stmt = stmt.options(selectinload(relation))
|
|
156
156
|
|
|
157
157
|
async with self.model_view.session_maker(expire_on_commit=False) as session:
|
|
158
158
|
result = await session.execute(stmt)
|
sqladmin/application.py
CHANGED
|
@@ -16,14 +16,14 @@ from typing import (
|
|
|
16
16
|
cast,
|
|
17
17
|
no_type_check,
|
|
18
18
|
)
|
|
19
|
-
from urllib.parse import urljoin
|
|
19
|
+
from urllib.parse import parse_qsl, urljoin
|
|
20
20
|
|
|
21
21
|
from jinja2 import ChoiceLoader, FileSystemLoader, PackageLoader
|
|
22
22
|
from sqlalchemy.engine import Engine
|
|
23
23
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
24
24
|
from sqlalchemy.orm import Session, sessionmaker
|
|
25
25
|
from starlette.applications import Starlette
|
|
26
|
-
from starlette.datastructures import URL, FormData, UploadFile
|
|
26
|
+
from starlette.datastructures import URL, FormData, MultiDict, UploadFile
|
|
27
27
|
from starlette.exceptions import HTTPException
|
|
28
28
|
from starlette.middleware import Middleware
|
|
29
29
|
from starlette.requests import Request
|
|
@@ -381,7 +381,7 @@ class Admin(BaseAdminView):
|
|
|
381
381
|
"message": exc.detail,
|
|
382
382
|
}
|
|
383
383
|
return await self.templates.TemplateResponse(
|
|
384
|
-
request, "error.html", context, status_code=exc.status_code
|
|
384
|
+
request, "sqladmin/error.html", context, status_code=exc.status_code
|
|
385
385
|
)
|
|
386
386
|
|
|
387
387
|
routes = [
|
|
@@ -428,7 +428,7 @@ class Admin(BaseAdminView):
|
|
|
428
428
|
async def index(self, request: Request) -> Response:
|
|
429
429
|
"""Index route which can be overridden to create dashboards."""
|
|
430
430
|
|
|
431
|
-
return await self.templates.TemplateResponse(request, "index.html")
|
|
431
|
+
return await self.templates.TemplateResponse(request, "sqladmin/index.html")
|
|
432
432
|
|
|
433
433
|
@login_required
|
|
434
434
|
async def list(self, request: Request) -> Response:
|
|
@@ -440,6 +440,14 @@ class Admin(BaseAdminView):
|
|
|
440
440
|
pagination = await model_view.list(request)
|
|
441
441
|
pagination.add_pagination_urls(request.url)
|
|
442
442
|
|
|
443
|
+
if (
|
|
444
|
+
pagination.page * pagination.page_size
|
|
445
|
+
> pagination.count + pagination.page_size
|
|
446
|
+
):
|
|
447
|
+
raise HTTPException(
|
|
448
|
+
status_code=400, detail="Invalid page or pageSize parameter"
|
|
449
|
+
)
|
|
450
|
+
|
|
443
451
|
context = {"model_view": model_view, "pagination": pagination}
|
|
444
452
|
return await self.templates.TemplateResponse(
|
|
445
453
|
request, model_view.list_template, context
|
|
@@ -485,7 +493,11 @@ class Admin(BaseAdminView):
|
|
|
485
493
|
|
|
486
494
|
await model_view.delete_model(request, pk)
|
|
487
495
|
|
|
488
|
-
|
|
496
|
+
referer_url = URL(request.headers.get("referer", ""))
|
|
497
|
+
referer_params = MultiDict(parse_qsl(referer_url.query))
|
|
498
|
+
url = URL(str(request.url_for("admin:list", identity=identity)))
|
|
499
|
+
url = url.include_query_params(**referer_params)
|
|
500
|
+
return Response(content=str(url))
|
|
489
501
|
|
|
490
502
|
@login_required
|
|
491
503
|
async def create(self, request: Request) -> Response:
|
|
@@ -542,7 +554,7 @@ class Admin(BaseAdminView):
|
|
|
542
554
|
identity = request.path_params["identity"]
|
|
543
555
|
model_view = self._find_model_view(identity)
|
|
544
556
|
|
|
545
|
-
model = await model_view.get_object_for_edit(request
|
|
557
|
+
model = await model_view.get_object_for_edit(request)
|
|
546
558
|
if not model:
|
|
547
559
|
raise HTTPException(status_code=404)
|
|
548
560
|
|
|
@@ -609,13 +621,13 @@ class Admin(BaseAdminView):
|
|
|
609
621
|
|
|
610
622
|
context = {}
|
|
611
623
|
if request.method == "GET":
|
|
612
|
-
return await self.templates.TemplateResponse(request, "login.html")
|
|
624
|
+
return await self.templates.TemplateResponse(request, "sqladmin/login.html")
|
|
613
625
|
|
|
614
626
|
ok = await self.authentication_backend.login(request)
|
|
615
627
|
if not ok:
|
|
616
628
|
context["error"] = "Invalid credentials."
|
|
617
629
|
return await self.templates.TemplateResponse(
|
|
618
|
-
request, "login.html", context, status_code=400
|
|
630
|
+
request, "sqladmin/login.html", context, status_code=400
|
|
619
631
|
)
|
|
620
632
|
|
|
621
633
|
return RedirectResponse(request.url_for("admin:index"), status_code=302)
|
sqladmin/forms.py
CHANGED
|
@@ -169,7 +169,7 @@ class ModelConverterBase:
|
|
|
169
169
|
if (column.primary_key or column.foreign_keys) and not form_include_pk:
|
|
170
170
|
return None
|
|
171
171
|
|
|
172
|
-
default = getattr(column, "default", None)
|
|
172
|
+
default = getattr(column, "default", None) or kwargs.get("default")
|
|
173
173
|
|
|
174
174
|
if default is not None:
|
|
175
175
|
# Only actually change default if it has an attribute named
|
sqladmin/helpers.py
CHANGED
|
@@ -241,10 +241,13 @@ def get_direction(prop: MODEL_PROPERTY) -> str:
|
|
|
241
241
|
|
|
242
242
|
def get_column_python_type(column: Column) -> type:
|
|
243
243
|
try:
|
|
244
|
-
if hasattr(column.type, "impl"):
|
|
245
|
-
return column.type.impl.python_type
|
|
246
244
|
return column.type.python_type
|
|
247
245
|
except NotImplementedError:
|
|
246
|
+
if hasattr(column.type, "impl"):
|
|
247
|
+
try:
|
|
248
|
+
return column.type.impl.python_type
|
|
249
|
+
except NotImplementedError:
|
|
250
|
+
...
|
|
248
251
|
return str
|
|
249
252
|
|
|
250
253
|
|
sqladmin/models.py
CHANGED
|
@@ -20,11 +20,12 @@ from urllib.parse import urlencode
|
|
|
20
20
|
import anyio
|
|
21
21
|
from sqlalchemy import Column, String, asc, cast, desc, func, inspect, or_
|
|
22
22
|
from sqlalchemy.exc import NoInspectionAvailable
|
|
23
|
-
from sqlalchemy.orm import
|
|
23
|
+
from sqlalchemy.orm import selectinload, sessionmaker
|
|
24
24
|
from sqlalchemy.orm.exc import DetachedInstanceError
|
|
25
25
|
from sqlalchemy.sql.elements import ClauseElement
|
|
26
26
|
from sqlalchemy.sql.expression import Select, select
|
|
27
27
|
from starlette.datastructures import URL
|
|
28
|
+
from starlette.exceptions import HTTPException
|
|
28
29
|
from starlette.requests import Request
|
|
29
30
|
from starlette.responses import StreamingResponse
|
|
30
31
|
from wtforms import Field, Form
|
|
@@ -414,17 +415,17 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
|
|
|
414
415
|
"""
|
|
415
416
|
|
|
416
417
|
# Templates
|
|
417
|
-
list_template: ClassVar[str] = "list.html"
|
|
418
|
-
"""List view template. Default is `list.html`."""
|
|
418
|
+
list_template: ClassVar[str] = "sqladmin/list.html"
|
|
419
|
+
"""List view template. Default is `sqladmin/list.html`."""
|
|
419
420
|
|
|
420
|
-
create_template: ClassVar[str] = "create.html"
|
|
421
|
-
"""Create view template. Default is `create.html`."""
|
|
421
|
+
create_template: ClassVar[str] = "sqladmin/create.html"
|
|
422
|
+
"""Create view template. Default is `sqladmin/create.html`."""
|
|
422
423
|
|
|
423
|
-
details_template: ClassVar[str] = "details.html"
|
|
424
|
-
"""Details view template. Default is `details.html`."""
|
|
424
|
+
details_template: ClassVar[str] = "sqladmin/details.html"
|
|
425
|
+
"""Details view template. Default is `sqladmin/details.html`."""
|
|
425
426
|
|
|
426
|
-
edit_template: ClassVar[str] = "edit.html"
|
|
427
|
-
"""Edit view template. Default is `edit.html`."""
|
|
427
|
+
edit_template: ClassVar[str] = "sqladmin/edit.html"
|
|
428
|
+
"""Edit view template. Default is `sqladmin/edit.html`."""
|
|
428
429
|
|
|
429
430
|
# Export
|
|
430
431
|
column_export_list: ClassVar[List[MODEL_ATTR]] = []
|
|
@@ -746,6 +747,17 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
|
|
|
746
747
|
|
|
747
748
|
return value
|
|
748
749
|
|
|
750
|
+
def validate_page_number(self, number: Union[str, None], default: int) -> int:
|
|
751
|
+
if not number:
|
|
752
|
+
return default
|
|
753
|
+
|
|
754
|
+
try:
|
|
755
|
+
return int(number)
|
|
756
|
+
except ValueError:
|
|
757
|
+
raise HTTPException(
|
|
758
|
+
status_code=400, detail="Invalid page or pageSize parameter"
|
|
759
|
+
)
|
|
760
|
+
|
|
749
761
|
async def count(self, request: Request, stmt: Optional[Select] = None) -> int:
|
|
750
762
|
if stmt is None:
|
|
751
763
|
stmt = self.count_query(request)
|
|
@@ -753,14 +765,14 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
|
|
|
753
765
|
return rows[0]
|
|
754
766
|
|
|
755
767
|
async def list(self, request: Request) -> Pagination:
|
|
756
|
-
page =
|
|
757
|
-
page_size =
|
|
768
|
+
page = self.validate_page_number(request.query_params.get("page"), 1)
|
|
769
|
+
page_size = self.validate_page_number(request.query_params.get("pageSize"), 0)
|
|
758
770
|
page_size = min(page_size or self.page_size, max(self.page_size_options))
|
|
759
771
|
search = request.query_params.get("search", None)
|
|
760
772
|
|
|
761
773
|
stmt = self.list_query(request)
|
|
762
774
|
for relation in self._list_relations:
|
|
763
|
-
stmt = stmt.options(
|
|
775
|
+
stmt = stmt.options(selectinload(relation))
|
|
764
776
|
|
|
765
777
|
stmt = self.sort_query(stmt, request)
|
|
766
778
|
|
|
@@ -790,7 +802,7 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
|
|
|
790
802
|
stmt = self.list_query(request).limit(limit)
|
|
791
803
|
|
|
792
804
|
for relation in self._list_relations:
|
|
793
|
-
stmt = stmt.options(
|
|
805
|
+
stmt = stmt.options(selectinload(relation))
|
|
794
806
|
|
|
795
807
|
rows = await self._run_query(stmt)
|
|
796
808
|
return rows
|
|
@@ -803,16 +815,12 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
|
|
|
803
815
|
stmt = self._stmt_by_identifier(value)
|
|
804
816
|
|
|
805
817
|
for relation in self._details_relations:
|
|
806
|
-
stmt = stmt.options(
|
|
818
|
+
stmt = stmt.options(selectinload(relation))
|
|
807
819
|
|
|
808
820
|
return await self._get_object_by_pk(stmt)
|
|
809
821
|
|
|
810
|
-
async def get_object_for_edit(self,
|
|
811
|
-
stmt = self.
|
|
812
|
-
|
|
813
|
-
for relation in self._form_relations:
|
|
814
|
-
stmt = stmt.options(joinedload(relation))
|
|
815
|
-
|
|
822
|
+
async def get_object_for_edit(self, request: Request) -> Any:
|
|
823
|
+
stmt = self.edit_form_query(request)
|
|
816
824
|
return await self._get_object_by_pk(stmt)
|
|
817
825
|
|
|
818
826
|
async def get_object_for_delete(self, value: Any) -> Any:
|
|
@@ -1045,6 +1053,18 @@ class ModelView(BaseView, metaclass=ModelViewMeta):
|
|
|
1045
1053
|
|
|
1046
1054
|
return select(self.model)
|
|
1047
1055
|
|
|
1056
|
+
def edit_form_query(self, request: Request) -> Select:
|
|
1057
|
+
"""
|
|
1058
|
+
The SQLAlchemy select expression used for the edit form page which can be
|
|
1059
|
+
customized. By default it will select the object by primary key(s) without any
|
|
1060
|
+
additional filters.
|
|
1061
|
+
"""
|
|
1062
|
+
|
|
1063
|
+
stmt = self._stmt_by_identifier(request.path_params["pk"])
|
|
1064
|
+
for relation in self._form_relations:
|
|
1065
|
+
stmt = stmt.options(selectinload(relation))
|
|
1066
|
+
return stmt
|
|
1067
|
+
|
|
1048
1068
|
def count_query(self, request: Request) -> Select:
|
|
1049
1069
|
"""
|
|
1050
1070
|
The SQLAlchemy select expression used for the count query
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% extends "layout.html" %}
|
|
1
|
+
{% extends "sqladmin/layout.html" %}
|
|
2
2
|
{% block content %}
|
|
3
3
|
<div class="col-12">
|
|
4
4
|
<div class="card">
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
{% for error in field.errors %}
|
|
27
27
|
<div class="invalid-feedback">{{ error }}</div>
|
|
28
28
|
{% endfor %}
|
|
29
|
+
{% if field.description %}
|
|
30
|
+
<small class="text-muted">{{ field.description }}</small>
|
|
31
|
+
{% endif %}
|
|
29
32
|
</div>
|
|
30
33
|
</div>
|
|
31
34
|
{% endfor %}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% extends "layout.html" %}
|
|
1
|
+
{% extends "sqladmin/layout.html" %}
|
|
2
2
|
{% block content %}
|
|
3
3
|
<div class="col-12">
|
|
4
4
|
<div class="card">
|
|
@@ -87,14 +87,14 @@
|
|
|
87
87
|
</div>
|
|
88
88
|
</div>
|
|
89
89
|
{% if model_view.can_delete %}
|
|
90
|
-
{% include 'modals/delete.html' %}
|
|
90
|
+
{% include 'sqladmin/modals/delete.html' %}
|
|
91
91
|
{% endif %}
|
|
92
92
|
|
|
93
93
|
{% for custom_action in model_view._custom_actions_in_detail %}
|
|
94
94
|
{% if custom_action in model_view._custom_actions_confirmation %}
|
|
95
95
|
{% with confirmation_message = model_view._custom_actions_confirmation[custom_action], custom_action=custom_action,
|
|
96
96
|
url=model_view._url_for_action(request, custom_action) + '?pks=' + (get_object_identifier(model) | string) %}
|
|
97
|
-
{% include 'modals/details_action_confirmation.html' %}
|
|
97
|
+
{% include 'sqladmin/modals/details_action_confirmation.html' %}
|
|
98
98
|
{% endwith %}
|
|
99
99
|
{% endif %}
|
|
100
100
|
{% endfor %}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% extends "layout.html" %}
|
|
1
|
+
{% extends "sqladmin/layout.html" %}
|
|
2
2
|
{% block content %}
|
|
3
3
|
<div class="col-12">
|
|
4
4
|
<div class="card">
|
|
@@ -26,6 +26,9 @@
|
|
|
26
26
|
{% for error in field.errors %}
|
|
27
27
|
<div class="invalid-feedback">{{ error }}</div>
|
|
28
28
|
{% endfor %}
|
|
29
|
+
{% if field.description %}
|
|
30
|
+
<small class="text-muted">{{ field.description }}</small>
|
|
31
|
+
{% endif %}
|
|
29
32
|
</div>
|
|
30
33
|
</div>
|
|
31
34
|
{% endfor %}
|
|
@@ -40,10 +43,12 @@
|
|
|
40
43
|
<div class="btn-group flex-wrap" data-toggle="buttons">
|
|
41
44
|
<input type="submit" name="save" value="Save" class="btn">
|
|
42
45
|
<input type="submit" name="save" value="Save and continue editing" class="btn">
|
|
43
|
-
{% if model_view.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
{% if model_view.can_create %}
|
|
47
|
+
{% if model_view.save_as %}
|
|
48
|
+
<input type="submit" name="save" value="Save as new" class="btn">
|
|
49
|
+
{% else %}
|
|
50
|
+
<input type="submit" name="save" value="Save and add another" class="btn">
|
|
51
|
+
{% endif %}
|
|
47
52
|
{% endif %}
|
|
48
53
|
</div>
|
|
49
54
|
</div>
|
|
@@ -52,4 +57,4 @@
|
|
|
52
57
|
</div>
|
|
53
58
|
</div>
|
|
54
59
|
</div>
|
|
55
|
-
{% endblock %}
|
|
60
|
+
{% endblock %}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
{% extends "base.html" %}
|
|
2
|
-
{% from '_macros.html' import display_menu %}
|
|
1
|
+
{% extends "sqladmin/base.html" %}
|
|
2
|
+
{% from 'sqladmin/_macros.html' import display_menu %}
|
|
3
3
|
{% block body %}
|
|
4
4
|
<div class="wrapper">
|
|
5
5
|
<aside class="navbar navbar-expand-lg navbar-vertical navbar-expand-md navbar-dark">
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% extends "layout.html" %}
|
|
1
|
+
{% extends "sqladmin/layout.html" %}
|
|
2
2
|
{% block content %}
|
|
3
3
|
<div class="col-12">
|
|
4
4
|
<div class="card">
|
|
@@ -95,10 +95,10 @@
|
|
|
95
95
|
<th>
|
|
96
96
|
{% if name in model_view._sort_fields %}
|
|
97
97
|
{% if request.query_params.get("sortBy") == name and request.query_params.get("sort") == "asc" %}
|
|
98
|
-
<a href="{{ request.url.include_query_params(sort='desc') }}"><i class="fa-solid fa-arrow-
|
|
98
|
+
<a href="{{ request.url.include_query_params(sort='desc') }}"><i class="fa-solid fa-arrow-up"></i> {{
|
|
99
99
|
label }}</a>
|
|
100
100
|
{% elif request.query_params.get("sortBy") == name and request.query_params.get("sort") == "desc" %}
|
|
101
|
-
<a href="{{ request.url.include_query_params(sort='asc') }}"><i class="fa-solid fa-arrow-
|
|
101
|
+
<a href="{{ request.url.include_query_params(sort='asc') }}"><i class="fa-solid fa-arrow-down"></i> {{ label
|
|
102
102
|
}}</a>
|
|
103
103
|
{% else %}
|
|
104
104
|
<a href="{{ request.url.include_query_params(sortBy=name, sort='asc') }}">{{ label }}</a>
|
|
@@ -207,16 +207,16 @@
|
|
|
207
207
|
</div>
|
|
208
208
|
</div>
|
|
209
209
|
{% if model_view.can_delete %}
|
|
210
|
-
{% include 'modals/delete.html' %}
|
|
210
|
+
{% include 'sqladmin/modals/delete.html' %}
|
|
211
211
|
{% endif %}
|
|
212
212
|
|
|
213
213
|
{% for custom_action in model_view._custom_actions_in_list %}
|
|
214
214
|
{% if custom_action in model_view._custom_actions_confirmation %}
|
|
215
215
|
{% with confirmation_message = model_view._custom_actions_confirmation[custom_action], custom_action=custom_action,
|
|
216
216
|
url=model_view._url_for_action(request, custom_action) %}
|
|
217
|
-
{% include 'modals/list_action_confirmation.html' %}
|
|
217
|
+
{% include 'sqladmin/modals/list_action_confirmation.html' %}
|
|
218
218
|
{% endwith %}
|
|
219
219
|
{% endif %}
|
|
220
220
|
{% endfor %}
|
|
221
221
|
</div>
|
|
222
|
-
{% endblock %}
|
|
222
|
+
{% endblock %}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
{% extends "base.html" %}
|
|
1
|
+
{% extends "sqladmin/base.html" %}
|
|
2
2
|
{% block body %}
|
|
3
3
|
<div class="d-flex align-items-center justify-content-center vh-100">
|
|
4
4
|
<form class="Fcol-lg-6 col-md-6 card card-md" action="{{ url_for('admin:login') }}" method="POST" autocomplete="off">
|
sqladmin/widgets.py
CHANGED
|
@@ -75,15 +75,23 @@ class FileInputWidget(widgets.FileInput):
|
|
|
75
75
|
"""
|
|
76
76
|
|
|
77
77
|
def __call__(self, field: Field, **kwargs: Any) -> str:
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
78
|
+
if not field.flags.required:
|
|
79
|
+
checkbox_id = f"{field.id}_checkbox"
|
|
80
|
+
checkbox_label = Markup(
|
|
81
|
+
f'<label class="form-check-label" for="{checkbox_id}">Clear</label>'
|
|
82
|
+
)
|
|
83
|
+
checkbox_input = Markup(
|
|
84
|
+
f'<input class="form-check-input" type="checkbox" id="{checkbox_id}" name="{checkbox_id}">' # noqa: E501
|
|
85
|
+
)
|
|
86
|
+
checkbox = Markup(
|
|
87
|
+
f'<div class="form-check">{checkbox_input}{checkbox_label}</div>'
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
checkbox = Markup()
|
|
91
|
+
|
|
92
|
+
if field.data:
|
|
93
|
+
current_value = Markup(f"<p>Currently: {field.data}</p>")
|
|
94
|
+
field.flags.required = False
|
|
95
|
+
return current_value + checkbox + super().__call__(field, **kwargs)
|
|
96
|
+
else:
|
|
97
|
+
return super().__call__(field, **kwargs)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: sqladmin
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.17.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,21 +1,21 @@
|
|
|
1
|
-
sqladmin/__init__.py,sha256=
|
|
1
|
+
sqladmin/__init__.py,sha256=p1XjIDLwQG28ayOpu2i60UG2NjL-mugVbHIaoARKpRo,216
|
|
2
2
|
sqladmin/_menu.py,sha256=srm7SUSN4RiP1UQ9y5uHcTX9sVVcvEV-6z5sfvLq-fc,2623
|
|
3
|
-
sqladmin/_queries.py,sha256=
|
|
3
|
+
sqladmin/_queries.py,sha256=ucZpjUZgEw8BVY4Ln6yHzgpOWUsadBI8-Cvy6x3LZe4,9673
|
|
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=oerBfp90Bow0CsDonBdurCl8XfzNvVWprzm8C3PJmlI,2552
|
|
7
|
-
sqladmin/application.py,sha256=
|
|
7
|
+
sqladmin/application.py,sha256=yhh6VXMlkKf-xVN1HTSthco7ELBT3QgMohzuz-7TXqc,27206
|
|
8
8
|
sqladmin/authentication.py,sha256=R4ad-8A5zWZ0vInK0pRj_oWirrQgWEY0Ng36j_NMC1U,2459
|
|
9
9
|
sqladmin/exceptions.py,sha256=6-E8m7rbWE3A7hNaSmB6CVqFzkEuwUpmU5AdGbouPCw,154
|
|
10
10
|
sqladmin/fields.py,sha256=5CFibyLYliD48Y6p2AKzmtdQeTHxxcn5_7LieQmBpGY,11752
|
|
11
11
|
sqladmin/formatters.py,sha256=K06la0mm9-Bs5UA9L6KGJC_X_lV3UHdJ3ENI6j9j2Zg,480
|
|
12
|
-
sqladmin/forms.py,sha256=
|
|
13
|
-
sqladmin/helpers.py,sha256=
|
|
14
|
-
sqladmin/models.py,sha256=
|
|
12
|
+
sqladmin/forms.py,sha256=cFUSS0QBX_g3B5hCuDN7ckD0Hz2l-HWPqqgbmE4lqKw,21429
|
|
13
|
+
sqladmin/helpers.py,sha256=wkMn0MfnRw4mC45rcusz4bV7Frb82kQvD04qTVFzc_4,8627
|
|
14
|
+
sqladmin/models.py,sha256=Hx7oUvLhYaAvts9KBWCtuP3kSCguadb70uUtmvJp8J8,37530
|
|
15
15
|
sqladmin/pagination.py,sha256=AmaZ5xNgPdBqTURYdOltz5IcSz8pY4qGQsr8evpUtHk,2256
|
|
16
16
|
sqladmin/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
17
17
|
sqladmin/templating.py,sha256=uIOfv7AFS4i_pErxdj5bcKDKxXz28BLlzCkLVFHqZsI,2244
|
|
18
|
-
sqladmin/widgets.py,sha256=
|
|
18
|
+
sqladmin/widgets.py,sha256=C_9GsqrnOiFkEHo6tBIkep9g4OCzMLeiB56lZM7bgqs,3110
|
|
19
19
|
sqladmin/statics/css/flatpickr.min.css,sha256=GzSkJVLJbxDk36qko2cnawOGiqz_Y8GsQv_jMTUrx1Q,16166
|
|
20
20
|
sqladmin/statics/css/fontawesome.min.css,sha256=CTSx_A06dm1B063156EVh15m6Y67pAjZZaQc89LLSrU,102217
|
|
21
21
|
sqladmin/statics/css/main.css,sha256=XziO3HgOtX6JmGb0lHSNzktBjevR_3XcmqmkV7E9jpc,45
|
|
@@ -31,20 +31,20 @@ sqladmin/statics/js/tabler.min.js,sha256=kuHV8gS0R5FupAkK6iExYXHKc5ZFbnSRYtVSorj
|
|
|
31
31
|
sqladmin/statics/webfonts/fa-brands-400.woff2,sha256=-q5vwKqUzFveUHZkfIF6IyBglqHL7aENHG89idYWPtE,109808
|
|
32
32
|
sqladmin/statics/webfonts/fa-regular-400.woff2,sha256=jn5eobFfYqsU29QXaOj7zSHMhZpOpdqBJFfucUKZ-zU,24948
|
|
33
33
|
sqladmin/statics/webfonts/fa-solid-900.woff2,sha256=cVKmkz7j1pDsKvPQnanXAXI9Fqo0EKbYDyj_iGbzuIA,150124
|
|
34
|
-
sqladmin/templates/_macros.html,sha256=nnUwiUAWBSkGD645U2VcuMkRoN3tT2X8RxFaCFvx9ww,1944
|
|
35
|
-
sqladmin/templates/base.html,sha256=MjcbhwWOEhwamvGevnH3FPlrjirvErhGhOdslpMLGrU,1592
|
|
36
|
-
sqladmin/templates/create.html,sha256=
|
|
37
|
-
sqladmin/templates/details.html,sha256=
|
|
38
|
-
sqladmin/templates/edit.html,sha256=
|
|
39
|
-
sqladmin/templates/error.html,sha256=
|
|
40
|
-
sqladmin/templates/index.html,sha256=
|
|
41
|
-
sqladmin/templates/layout.html,sha256=
|
|
42
|
-
sqladmin/templates/list.html,sha256=
|
|
43
|
-
sqladmin/templates/login.html,sha256=
|
|
44
|
-
sqladmin/templates/modals/delete.html,sha256=jTuv6geT-AhK5HTgRmntrJ8CEi98-kwKrVDrzkOQWhw,1092
|
|
45
|
-
sqladmin/templates/modals/details_action_confirmation.html,sha256=mN8LJ5OqypxNLAg2_GYZgQmGeK4E6t7JL5RmOEYuliM,1020
|
|
46
|
-
sqladmin/templates/modals/list_action_confirmation.html,sha256=U52LLNmpLaMuUZSVtGK15oLXsEu6m2S3l9zj9sjN6uM,1078
|
|
47
|
-
sqladmin-0.
|
|
48
|
-
sqladmin-0.
|
|
49
|
-
sqladmin-0.
|
|
50
|
-
sqladmin-0.
|
|
34
|
+
sqladmin/templates/sqladmin/_macros.html,sha256=nnUwiUAWBSkGD645U2VcuMkRoN3tT2X8RxFaCFvx9ww,1944
|
|
35
|
+
sqladmin/templates/sqladmin/base.html,sha256=MjcbhwWOEhwamvGevnH3FPlrjirvErhGhOdslpMLGrU,1592
|
|
36
|
+
sqladmin/templates/sqladmin/create.html,sha256=YvsGQ4lCVXgDXDsUvOcpGPOIx9KEsrYpBGYQ4CO3jwk,1970
|
|
37
|
+
sqladmin/templates/sqladmin/details.html,sha256=RuWdlsZw5m_gm24Tdn3APNlfKtTHfYw7BnZB0_Tj6Hw,3932
|
|
38
|
+
sqladmin/templates/sqladmin/edit.html,sha256=ZA_Y7SlMSgbUU5PET7JzvhIRFMTVw8BJ_46HvF-hhDY,2226
|
|
39
|
+
sqladmin/templates/sqladmin/error.html,sha256=gb-172SMuQKncv0QE8DQdQXeM-fw7oXC0LPLO3ia0IM,290
|
|
40
|
+
sqladmin/templates/sqladmin/index.html,sha256=vh_IhhYmHPOkdZNrXSEc4e9gXXeZ-nsRBCsJQ_mC7YI,71
|
|
41
|
+
sqladmin/templates/sqladmin/layout.html,sha256=iBIhypkXp6O3hAHDdMNc4pWd9yxt5mQy7o2lBQD-6Ec,1994
|
|
42
|
+
sqladmin/templates/sqladmin/list.html,sha256=L51ubV1OyeDYbuOscw9N1Ar3tU8mgWSRXeuCUYs_iCQ,10262
|
|
43
|
+
sqladmin/templates/sqladmin/login.html,sha256=Y_hlcIapfVFPNbSIbCe4Tbj5DLLD46emkSlL5-RP4iY,1514
|
|
44
|
+
sqladmin/templates/sqladmin/modals/delete.html,sha256=jTuv6geT-AhK5HTgRmntrJ8CEi98-kwKrVDrzkOQWhw,1092
|
|
45
|
+
sqladmin/templates/sqladmin/modals/details_action_confirmation.html,sha256=mN8LJ5OqypxNLAg2_GYZgQmGeK4E6t7JL5RmOEYuliM,1020
|
|
46
|
+
sqladmin/templates/sqladmin/modals/list_action_confirmation.html,sha256=U52LLNmpLaMuUZSVtGK15oLXsEu6m2S3l9zj9sjN6uM,1078
|
|
47
|
+
sqladmin-0.17.0.dist-info/METADATA,sha256=nNDF1rnQCDmFiJa0B_9XBs-SCPoFGy5dUrw7VOjY9W0,5270
|
|
48
|
+
sqladmin-0.17.0.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
|
|
49
|
+
sqladmin-0.17.0.dist-info/licenses/LICENSE.md,sha256=4zzpHQMPtND4hzIgJA5qnb4R_wRBWJlYGqNrZolBeP8,1488
|
|
50
|
+
sqladmin-0.17.0.dist-info/RECORD,,
|
sqladmin/templates/index.html
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|