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 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.16.1"
4
+ __version__ = "0.17.0"
5
5
 
6
6
  __all__ = [
7
7
  "Admin",
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, joinedload
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(joinedload(relation))
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
- return Response(content=str(request.url_for("admin:list", identity=identity)))
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.path_params["pk"])
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 joinedload, sessionmaker
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 = int(request.query_params.get("page", 1))
757
- page_size = int(request.query_params.get("pageSize", 0))
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(joinedload(relation))
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(joinedload(relation))
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(joinedload(relation))
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, value: Any) -> Any:
811
- stmt = self._stmt_by_identifier(value)
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.save_as %}
44
- <input type="submit" name="save" value="Save as new" class="btn">
45
- {% else %}
46
- <input type="submit" name="save" value="Save and add another" class="btn">
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,4 +1,4 @@
1
- {% extends "layout.html" %}
1
+ {% extends "sqladmin/layout.html" %}
2
2
  {% block body %}
3
3
  <div class="page page-center">
4
4
  <div class="container-tight py-4">
@@ -0,0 +1,3 @@
1
+ {% extends "sqladmin/layout.html" %}
2
+ {% block content %}
3
+ {% 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-down"></i> {{
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-up"></i> {{ label
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
- file_input = super().__call__(field, **kwargs)
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
- return file_input + checkbox
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
1
+ Metadata-Version: 2.3
2
2
  Name: sqladmin
3
- Version: 0.16.1
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=MLyzIi0PmD77EY7X-MF-yDRcF01bQb3ORV62cL7I5-E,216
1
+ sqladmin/__init__.py,sha256=p1XjIDLwQG28ayOpu2i60UG2NjL-mugVbHIaoARKpRo,216
2
2
  sqladmin/_menu.py,sha256=srm7SUSN4RiP1UQ9y5uHcTX9sVVcvEV-6z5sfvLq-fc,2623
3
- sqladmin/_queries.py,sha256=xZNv4eahSGZCffdsYi5h-6f951RHrRmT4AtLOtqYr8s,9669
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=QDiyrI15OSSUdGOyECqFeOmufc0dC04lw9-hs18hl6M,26700
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=K_uq8AdTvBmsjZiIxKROwDfAZSZ5mlMt951Tga_rQMU,21404
13
- sqladmin/helpers.py,sha256=kO10XpKr9hlWFamJMXA8QiUAcqBcS1vO6C7QjjFfqIk,8546
14
- sqladmin/models.py,sha256=Ofh-6XwKGF9c0KyXXwmyedrGMlChrcmjze-_2qxSdug,36656
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=JB9lYUuZGsxSvBIDosvNYYDBPjlOr10ALoDpkugoB_w,2797
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=W2-VqRfH0lpBihOx7c-Yat98c4m9iEbftnkWRo3erbg,1822
37
- sqladmin/templates/details.html,sha256=XMgRfbPY5_XIO5SyLr4Jc0l6ZlwraCTZY-0yEYLWvxw,3905
38
- sqladmin/templates/edit.html,sha256=Ao2nM06KOhp14MbRH71JtqKvX61By4hF5ysSTW11pyk,1996
39
- sqladmin/templates/error.html,sha256=Rej-R7NQU3JZRE_YRF_JIErWIuKC6dLxM10yl9k_U6E,281
40
- sqladmin/templates/index.html,sha256=NisVw6t-EbkvOvR-yCJYgVLB0KRH3KvH-pGTudwL03s,62
41
- sqladmin/templates/layout.html,sha256=R7pCnARoybiQssUpF-KAB0S1xl1bBlZtHJ_k-SuBMd4,1976
42
- sqladmin/templates/list.html,sha256=C_sjcnf85q9GiBBiOvDZRdLpWj49JuiyysesPvqT1Ik,10234
43
- sqladmin/templates/login.html,sha256=XSxiQAukaeFGadc4CDFrs_VQBgTrc8FaUqAGuxDiqjY,1505
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.16.1.dist-info/METADATA,sha256=106qBaYm6RKnoqOAtI6EMFb2VMu2tH-mLbFYQG6B59k,5270
48
- sqladmin-0.16.1.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
49
- sqladmin-0.16.1.dist-info/licenses/LICENSE.md,sha256=4zzpHQMPtND4hzIgJA5qnb4R_wRBWJlYGqNrZolBeP8,1488
50
- sqladmin-0.16.1.dist-info/RECORD,,
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,,
@@ -1,4 +1,4 @@
1
1
  Wheel-Version: 1.0
2
- Generator: hatchling 1.21.1
2
+ Generator: hatchling 1.24.2
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
@@ -1,3 +0,0 @@
1
- {% extends "layout.html" %}
2
- {% block content %}
3
- {% endblock %}
File without changes