brilliance-admin 0.39.0__tar.gz → 0.44.6__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 (125) hide show
  1. brilliance_admin-0.44.6/LICENSE +21 -0
  2. brilliance_admin-0.44.6/PKG-INFO +158 -0
  3. brilliance_admin-0.44.6/README.md +124 -0
  4. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/__init__.py +2 -2
  5. brilliance_admin-0.44.6/brilliance_admin/api/routers.py +18 -0
  6. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/utils.py +1 -1
  7. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/views/auth.py +6 -6
  8. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/views/autocomplete.py +9 -9
  9. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/views/graphs.py +8 -8
  10. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/views/index.py +11 -4
  11. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/views/schema.py +3 -3
  12. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/views/settings.py +5 -5
  13. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/views/table.py +24 -23
  14. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/auth.py +1 -1
  15. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/exceptions.py +4 -4
  16. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/__init__.py +1 -0
  17. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/auth.py +7 -8
  18. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/autocomplete.py +10 -6
  19. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/fields.py +45 -28
  20. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/fields_schema.py +27 -18
  21. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/table/base.py +8 -8
  22. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/table/create.py +11 -10
  23. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/table/delete.py +4 -4
  24. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/table/list.py +39 -21
  25. brilliance_admin-0.44.6/brilliance_admin/integrations/sqlalchemy/table/retrieve.py +83 -0
  26. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/table/update.py +12 -11
  27. brilliance_admin-0.44.6/brilliance_admin/locales/en.yml +32 -0
  28. brilliance_admin-0.44.6/brilliance_admin/locales/ru.yml +32 -0
  29. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/__init__.py +2 -2
  30. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/admin_schema.py +67 -51
  31. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/category.py +90 -16
  32. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/graphs/category_graphs.py +10 -10
  33. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/table/admin_action.py +8 -7
  34. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/table/category_table.py +26 -24
  35. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/table/fields/base.py +79 -35
  36. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/table/fields/function_field.py +3 -3
  37. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/table/fields_schema.py +18 -11
  38. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/table/table_models.py +1 -1
  39. brilliance_admin-0.39.0/admin_panel/static/index-SCeDXvci.js → brilliance_admin-0.44.6/brilliance_admin/static/index-BV43pxcV.js +159 -159
  40. brilliance_admin-0.39.0/admin_panel/static/index-BrXRRuaE.css → brilliance_admin-0.44.6/brilliance_admin/static/index-P_wdMBbz.css +1 -1
  41. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/templates/index.html +2 -2
  42. brilliance_admin-0.44.6/brilliance_admin/translations.py +115 -0
  43. brilliance_admin-0.44.6/brilliance_admin/utils.py +191 -0
  44. brilliance_admin-0.44.6/brilliance_admin.egg-info/PKG-INFO +158 -0
  45. brilliance_admin-0.44.6/brilliance_admin.egg-info/SOURCES.txt +84 -0
  46. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/brilliance_admin.egg-info/requires.txt +7 -3
  47. brilliance_admin-0.44.6/brilliance_admin.egg-info/top_level.txt +1 -0
  48. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/pyproject.toml +16 -8
  49. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/tests/test_action.py +2 -2
  50. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/tests/test_payments_fields_schema.py +5 -34
  51. brilliance_admin-0.44.6/tests/test_settings.py +48 -0
  52. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/tests/test_sqlalcmeny_auth.py +6 -6
  53. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/tests/test_sqlalcmeny_crud.py +38 -24
  54. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/tests/test_sqlalcmeny_filters.py +15 -21
  55. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/tests/test_sqlalcmeny_schema.py +56 -7
  56. brilliance_admin-0.44.6/tests/test_translations.py +41 -0
  57. brilliance_admin-0.39.0/.configs/docker/Dockerfile +0 -22
  58. brilliance_admin-0.39.0/.configs/docker/docker-compose.yml +0 -35
  59. brilliance_admin-0.39.0/.configs/nginx/example.conf +0 -25
  60. brilliance_admin-0.39.0/.env +0 -0
  61. brilliance_admin-0.39.0/.github/workflows/certbot.yml +0 -27
  62. brilliance_admin-0.39.0/.github/workflows/deploy.yml +0 -127
  63. brilliance_admin-0.39.0/.github/workflows/install-docker.yml +0 -26
  64. brilliance_admin-0.39.0/.gitignore +0 -11
  65. brilliance_admin-0.39.0/.isort.cfg +0 -7
  66. brilliance_admin-0.39.0/.python-version +0 -1
  67. brilliance_admin-0.39.0/LICENSE +0 -17
  68. brilliance_admin-0.39.0/PKG-INFO +0 -76
  69. brilliance_admin-0.39.0/README.md +0 -46
  70. brilliance_admin-0.39.0/admin_panel/api/routers.py +0 -18
  71. brilliance_admin-0.39.0/admin_panel/integrations/sqlalchemy/table/retrieve.py +0 -61
  72. brilliance_admin-0.39.0/admin_panel/schema/group.py +0 -67
  73. brilliance_admin-0.39.0/admin_panel/static/favicon.ico +0 -0
  74. brilliance_admin-0.39.0/admin_panel/translations.py +0 -145
  75. brilliance_admin-0.39.0/admin_panel/utils.py +0 -50
  76. brilliance_admin-0.39.0/brilliance_admin.egg-info/PKG-INFO +0 -76
  77. brilliance_admin-0.39.0/brilliance_admin.egg-info/SOURCES.txt +0 -109
  78. brilliance_admin-0.39.0/brilliance_admin.egg-info/top_level.txt +0 -1
  79. brilliance_admin-0.39.0/example/__init__.py +0 -0
  80. brilliance_admin-0.39.0/example/main.py +0 -142
  81. brilliance_admin-0.39.0/example/phrases.py +0 -112
  82. brilliance_admin-0.39.0/example/sections/__init__.py +0 -0
  83. brilliance_admin-0.39.0/example/sections/currency.py +0 -20
  84. brilliance_admin-0.39.0/example/sections/graphs.py +0 -136
  85. brilliance_admin-0.39.0/example/sections/merchant.py +0 -45
  86. brilliance_admin-0.39.0/example/sections/models.py +0 -194
  87. brilliance_admin-0.39.0/example/sections/payments.py +0 -199
  88. brilliance_admin-0.39.0/example/sections/terminal.py +0 -41
  89. brilliance_admin-0.39.0/example/sections/users.py +0 -25
  90. brilliance_admin-0.39.0/example/sqlite.py +0 -45
  91. brilliance_admin-0.39.0/example/utils.py +0 -26
  92. brilliance_admin-0.39.0/tests/__init__.py +0 -0
  93. brilliance_admin-0.39.0/tests/conftest.py +0 -12
  94. brilliance_admin-0.39.0/tests/test_translations.py +0 -90
  95. brilliance_admin-0.39.0/uv.lock +0 -773
  96. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/__init__.py +0 -0
  97. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/api/views/__init__.py +0 -0
  98. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/docs.py +0 -0
  99. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/__init__.py +0 -0
  100. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/integrations/sqlalchemy/table/__init__.py +0 -0
  101. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/graphs/__init__.py +0 -0
  102. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/table/__init__.py +0 -0
  103. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/schema/table/fields/__init__.py +0 -0
  104. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/materialdesignicons-webfont-CYDMK1kx.woff2 +0 -0
  105. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/materialdesignicons-webfont-CgCzGbLl.woff +0 -0
  106. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/materialdesignicons-webfont-D3kAzl71.ttf +0 -0
  107. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/materialdesignicons-webfont-DttUABo4.eot +0 -0
  108. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/dark-first/content.min.css +0 -0
  109. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/dark-first/skin.min.css +0 -0
  110. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/dark-slim/content.min.css +0 -0
  111. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/dark-slim/skin.min.css +0 -0
  112. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/img/example.png +0 -0
  113. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/img/tinymce.woff2 +0 -0
  114. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/lightgray/content.min.css +0 -0
  115. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/lightgray/fonts/tinymce.woff +0 -0
  116. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/lightgray/skin.min.css +0 -0
  117. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/plugins/accordion/css/accordion.css +0 -0
  118. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/plugins/accordion/plugin.js +0 -0
  119. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/plugins/codesample/css/prism.css +0 -0
  120. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/plugins/customLink/css/link.css +0 -0
  121. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/plugins/customLink/plugin.js +0 -0
  122. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/tinymce/tinymce.min.js +0 -0
  123. {brilliance_admin-0.39.0/admin_panel → brilliance_admin-0.44.6/brilliance_admin}/static/vanilla-picker-B6E6ObS_.js +0 -0
  124. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/brilliance_admin.egg-info/dependency_links.txt +0 -0
  125. {brilliance_admin-0.39.0 → brilliance_admin-0.44.6}/setup.cfg +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Brilliance Admin
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NON INFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,158 @@
1
+ Metadata-Version: 2.4
2
+ Name: brilliance-admin
3
+ Version: 0.44.6
4
+ Summary: Simple and lightweight data managment framework powered by FastAPI and Vue3 Vuetify all-in-one. Some call it heavenly in its brilliance.
5
+ License-Expression: MIT
6
+ Requires-Python: >=3.10
7
+ Description-Content-Type: text/markdown
8
+ License-File: LICENSE
9
+ Requires-Dist: asgiref>=3.11
10
+ Requires-Dist: fastapi>=0.115
11
+ Requires-Dist: jinja2>=3.1
12
+ Requires-Dist: PyYAML>=6.0
13
+ Provides-Extra: example
14
+ Requires-Dist: uvicorn>=0.34.0; extra == "example"
15
+ Requires-Dist: faker>=38.2.0; extra == "example"
16
+ Requires-Dist: pyjwt>=2.10.1; extra == "example"
17
+ Requires-Dist: structlog>=25.5.0; extra == "example"
18
+ Requires-Dist: rich>=14.2.0; extra == "example"
19
+ Requires-Dist: asyncpg>=0.31.0; extra == "example"
20
+ Requires-Dist: pydantic-settings>=2.12.0; extra == "example"
21
+ Requires-Dist: twine; extra == "example"
22
+ Provides-Extra: tests
23
+ Requires-Dist: pytest>=8.4.2; extra == "tests"
24
+ Requires-Dist: pytest-asyncio>=1.2.0; extra == "tests"
25
+ Requires-Dist: httpx>=0.28.1; extra == "tests"
26
+ Requires-Dist: pytest-mock>=3.15.1; extra == "tests"
27
+ Requires-Dist: sqlalchemy>=2.0.41; extra == "tests"
28
+ Requires-Dist: aiosqlite>=0.22.1; extra == "tests"
29
+ Requires-Dist: factory-boy>=3.3.3; extra == "tests"
30
+ Requires-Dist: pyjwt>=2.10.1; extra == "tests"
31
+ Provides-Extra: scalar
32
+ Requires-Dist: scalar-fastapi>=1.5.0; extra == "scalar"
33
+ Dynamic: license-file
34
+
35
+ <div align="center">
36
+ <img src="https://github.com/brilliance-admin/backend-python/blob/main/example/static/logo-outline.png?raw=true"
37
+ alt="Brilliance Admin"
38
+ width="600">
39
+
40
+ [![PyPI](https://img.shields.io/pypi/v/brilliance-admin)](https://pypi.org/project/brilliance-admin/)
41
+ [![CI](https://github.com/brilliance-admin/backend-python/actions/workflows/deploy.yml/badge.svg)](https://github.com/brilliance-admin/backend-python/actions)
42
+
43
+ Simple and lightweight data managment framework powered by `FastAPI` and `Vue3` `Vuetify` all-in-one. \
44
+ Integrated with `SQLAlchemy`. Inspaired by Django Admin and DRF.\
45
+ _Some call it heavenly in its brilliance._
46
+
47
+ ### [Live Demo](https://brilliance-admin.com/) | [Demo Sources](https://github.com/brilliance-admin/backend-python/tree/main/example) | [Documentation](https://docs.brilliance-admin.com/)
48
+
49
+ <img src="https://github.com/brilliance-admin/backend-python/blob/main/screenshots/websitemockupgenerator.png?raw=true"
50
+ alt="Preview">
51
+
52
+ </div>
53
+
54
+ ### Brilliance Admin provides
55
+
56
+ A quick way to create a data management interface using:
57
+
58
+ - Admin page - endpoint with a prebuilt SPA [frontend Vue3 + Vuetify](https://github.com/brilliance-admin/frontend) <br>
59
+ This endpoint can be added to any ASGI compatable backend. For existing project or standalone admin app.
60
+ - API to fetch the UI JSON schema
61
+ - API methods for that UI to work with (to read and modify data)
62
+
63
+ ## Key ideas
64
+
65
+ - **API Oriented** <br>
66
+ Data generation/updating API separated from rendering fontend with zero hardcode, this makes it possible to have a single frontend with multiple backend implementations in different languages and makes test coverage easier.
67
+ - **Rich visualization** <br>
68
+ Providing rich and convenient ways to display and manage data (tables, charts, etc) from any data source.
69
+ - **UI JSON Schema** <br>
70
+ Represents the data describing the structure of entire admin panel UI. <br>
71
+ You only need to specify what should be rendered. The frontend will display it and automatically request data from the backend for rendering or updates.
72
+ - **ORM** <br>
73
+ Automatic generation from ORM for schema UI frontend and backend methods for CRUD operations.
74
+ - **Minimal boilerplate** <br>
75
+ Focused on simplified, but rich configuration.
76
+
77
+ ## Features
78
+
79
+ * Tables with full CRUD support, including filtering, sorting, and pagination.
80
+ * Ability to define custom table actions with forms, response messages, and file downloads.
81
+ * Graphs via ChartJS
82
+ * Localization support
83
+ * Adapted for different screen sizes and mobile devices
84
+ * Auth via any account data source
85
+
86
+ **Integrations:**
87
+
88
+ * **SQLAlchemy** - schema autogeneration for tables + CRUD operations + authorization
89
+
90
+ **Planned:**
91
+
92
+ * Dashboard features
93
+ * Role-based access permissions system via interface
94
+ * Backend interface for storing and viewing action history in the admin interface
95
+ * Nested data support for creation and detail views (inline editing), nested CRUD workflows
96
+ * Django ORM integration
97
+ * Support for Oauth providers
98
+
99
+ ## Installation:
100
+ ``` shell
101
+ pip install brilliance-admin
102
+ ```
103
+
104
+ ## Usage example
105
+
106
+ You need to generate `AdminSchema` instance:
107
+ ``` python
108
+ from brilliance_admin import schema
109
+
110
+
111
+ class CategoryExample(schema.CategoryTable):
112
+ "Implementation of get_list and retrieve; update and create are optional"
113
+
114
+
115
+ admin_schema = schema.AdminSchema(
116
+ title='Admin Panel',
117
+ auth=YourAdminAuthentication(),
118
+ categories=[
119
+ schema.Category(
120
+ slug='example',
121
+ categories=[
122
+ CategoryExample(),
123
+ ]
124
+ ),
125
+ ],
126
+ )
127
+
128
+ admin_app = admin_schema.generate_app()
129
+
130
+ # Your FastAPI app (Any ASGI framework can be used)
131
+ app = FastAPI()
132
+ app.mount('/admin', admin_app)
133
+ ```
134
+
135
+ For more details, check out our [how-to-start documentation](https://docs.brilliance-admin.com/how-to-start/)
136
+
137
+ ## Comparison of Similar Projects
138
+
139
+ The project closest in concept is [React Admin](https://github.com/marmelab/react-admin). <br>
140
+ It is an SPA frontend that store the schema UI inside and works with separate API backend providers.
141
+
142
+ The key difference of Brilliance Admin is that its all-in-one. <br>
143
+ It is more focused on rapid setup for data management, without the need to work with frontend configuration, while it still available.
144
+
145
+ ## Comparison of Similar Python Projects
146
+
147
+ | Criterion | Brilliance Admin | Django Admin | FastAPI Admin | Starlette Admin | SQLAdmin |
148
+ |---------|------------------|--------------|---------------|-----------------|----------|
149
+ | Base framework | FastAPI | Django | FastAPI | Starlette | FastAPI |
150
+ | ASGI compatible | Yes | Partial | Yes | Yes | Yes |
151
+ | Rendering model | Prebuilt Vue 3 + Vuetify SPA + Jinja2 | Server-side Django templates | Server-side Jinja2 templates + Tabler UI | Server-side Jinja2 templates + Tabler UI | Server-side Jinja2 templates + Bootstrap |
152
+ | Frontend architecture | Separate frontend (SPA) | Classic server-rendered UI | Server-rendered UI with JS interactivity | Server-rendered UI with JS interactivity | Server-rendered UI |
153
+ | Data source | Any source + SQLAlchemy | Django ORM | Tortoise ORM | Any source + SQLAlchemy, MongoDB | SQLAlchemy |
154
+ | Multiple databases per model | Yes | Database routers | No (global engine) | Yes (session per ModelView) | No (single engine per Admin) |
155
+ | Schema generation | User-defined format | From Django models | From ORM models | User-defined format | From SQLAlchemy models |
156
+ | Async support | Yes | No | Yes | Yes | Yes |
157
+ | API-first approach | Yes | No | Partially | Partially | No |
158
+ | Built-in Localization | Yes | Yes | No | No | No |
@@ -0,0 +1,124 @@
1
+ <div align="center">
2
+ <img src="https://github.com/brilliance-admin/backend-python/blob/main/example/static/logo-outline.png?raw=true"
3
+ alt="Brilliance Admin"
4
+ width="600">
5
+
6
+ [![PyPI](https://img.shields.io/pypi/v/brilliance-admin)](https://pypi.org/project/brilliance-admin/)
7
+ [![CI](https://github.com/brilliance-admin/backend-python/actions/workflows/deploy.yml/badge.svg)](https://github.com/brilliance-admin/backend-python/actions)
8
+
9
+ Simple and lightweight data managment framework powered by `FastAPI` and `Vue3` `Vuetify` all-in-one. \
10
+ Integrated with `SQLAlchemy`. Inspaired by Django Admin and DRF.\
11
+ _Some call it heavenly in its brilliance._
12
+
13
+ ### [Live Demo](https://brilliance-admin.com/) | [Demo Sources](https://github.com/brilliance-admin/backend-python/tree/main/example) | [Documentation](https://docs.brilliance-admin.com/)
14
+
15
+ <img src="https://github.com/brilliance-admin/backend-python/blob/main/screenshots/websitemockupgenerator.png?raw=true"
16
+ alt="Preview">
17
+
18
+ </div>
19
+
20
+ ### Brilliance Admin provides
21
+
22
+ A quick way to create a data management interface using:
23
+
24
+ - Admin page - endpoint with a prebuilt SPA [frontend Vue3 + Vuetify](https://github.com/brilliance-admin/frontend) <br>
25
+ This endpoint can be added to any ASGI compatable backend. For existing project or standalone admin app.
26
+ - API to fetch the UI JSON schema
27
+ - API methods for that UI to work with (to read and modify data)
28
+
29
+ ## Key ideas
30
+
31
+ - **API Oriented** <br>
32
+ Data generation/updating API separated from rendering fontend with zero hardcode, this makes it possible to have a single frontend with multiple backend implementations in different languages and makes test coverage easier.
33
+ - **Rich visualization** <br>
34
+ Providing rich and convenient ways to display and manage data (tables, charts, etc) from any data source.
35
+ - **UI JSON Schema** <br>
36
+ Represents the data describing the structure of entire admin panel UI. <br>
37
+ You only need to specify what should be rendered. The frontend will display it and automatically request data from the backend for rendering or updates.
38
+ - **ORM** <br>
39
+ Automatic generation from ORM for schema UI frontend and backend methods for CRUD operations.
40
+ - **Minimal boilerplate** <br>
41
+ Focused on simplified, but rich configuration.
42
+
43
+ ## Features
44
+
45
+ * Tables with full CRUD support, including filtering, sorting, and pagination.
46
+ * Ability to define custom table actions with forms, response messages, and file downloads.
47
+ * Graphs via ChartJS
48
+ * Localization support
49
+ * Adapted for different screen sizes and mobile devices
50
+ * Auth via any account data source
51
+
52
+ **Integrations:**
53
+
54
+ * **SQLAlchemy** - schema autogeneration for tables + CRUD operations + authorization
55
+
56
+ **Planned:**
57
+
58
+ * Dashboard features
59
+ * Role-based access permissions system via interface
60
+ * Backend interface for storing and viewing action history in the admin interface
61
+ * Nested data support for creation and detail views (inline editing), nested CRUD workflows
62
+ * Django ORM integration
63
+ * Support for Oauth providers
64
+
65
+ ## Installation:
66
+ ``` shell
67
+ pip install brilliance-admin
68
+ ```
69
+
70
+ ## Usage example
71
+
72
+ You need to generate `AdminSchema` instance:
73
+ ``` python
74
+ from brilliance_admin import schema
75
+
76
+
77
+ class CategoryExample(schema.CategoryTable):
78
+ "Implementation of get_list and retrieve; update and create are optional"
79
+
80
+
81
+ admin_schema = schema.AdminSchema(
82
+ title='Admin Panel',
83
+ auth=YourAdminAuthentication(),
84
+ categories=[
85
+ schema.Category(
86
+ slug='example',
87
+ categories=[
88
+ CategoryExample(),
89
+ ]
90
+ ),
91
+ ],
92
+ )
93
+
94
+ admin_app = admin_schema.generate_app()
95
+
96
+ # Your FastAPI app (Any ASGI framework can be used)
97
+ app = FastAPI()
98
+ app.mount('/admin', admin_app)
99
+ ```
100
+
101
+ For more details, check out our [how-to-start documentation](https://docs.brilliance-admin.com/how-to-start/)
102
+
103
+ ## Comparison of Similar Projects
104
+
105
+ The project closest in concept is [React Admin](https://github.com/marmelab/react-admin). <br>
106
+ It is an SPA frontend that store the schema UI inside and works with separate API backend providers.
107
+
108
+ The key difference of Brilliance Admin is that its all-in-one. <br>
109
+ It is more focused on rapid setup for data management, without the need to work with frontend configuration, while it still available.
110
+
111
+ ## Comparison of Similar Python Projects
112
+
113
+ | Criterion | Brilliance Admin | Django Admin | FastAPI Admin | Starlette Admin | SQLAdmin |
114
+ |---------|------------------|--------------|---------------|-----------------|----------|
115
+ | Base framework | FastAPI | Django | FastAPI | Starlette | FastAPI |
116
+ | ASGI compatible | Yes | Partial | Yes | Yes | Yes |
117
+ | Rendering model | Prebuilt Vue 3 + Vuetify SPA + Jinja2 | Server-side Django templates | Server-side Jinja2 templates + Tabler UI | Server-side Jinja2 templates + Tabler UI | Server-side Jinja2 templates + Bootstrap |
118
+ | Frontend architecture | Separate frontend (SPA) | Classic server-rendered UI | Server-rendered UI with JS interactivity | Server-rendered UI with JS interactivity | Server-rendered UI |
119
+ | Data source | Any source + SQLAlchemy | Django ORM | Tortoise ORM | Any source + SQLAlchemy, MongoDB | SQLAlchemy |
120
+ | Multiple databases per model | Yes | Database routers | No (global engine) | Yes (session per ModelView) | No (single engine per Admin) |
121
+ | Schema generation | User-defined format | From Django models | From ORM models | User-defined format | From SQLAlchemy models |
122
+ | Async support | Yes | No | Yes | Yes | Yes |
123
+ | API-first approach | Yes | No | Partially | Partially | No |
124
+ | Built-in Localization | Yes | Yes | No | No | No |
@@ -1,4 +1,4 @@
1
1
  # pylint: disable=wildcard-import, unused-wildcard-import, unused-import
2
2
  # flake8: noqa: F405
3
- from admin_panel.integrations import sqlalchemy
4
- from admin_panel import schema
3
+ from brilliance_admin.integrations import sqlalchemy
4
+ from brilliance_admin import schema
@@ -0,0 +1,18 @@
1
+ from fastapi import APIRouter
2
+
3
+ from .views.schema import router as schema_router
4
+ from .views.table import router as schema_table
5
+ from .views.auth import router as schema_auth
6
+ from .views.autocomplete import router as schema_autocomplete
7
+ from .views.graphs import router as schema_graphs
8
+ from .views.settings import router as schema_settings
9
+ from .views.index import router as schema_index
10
+
11
+ brilliance_admin_router = APIRouter()
12
+ brilliance_admin_router.include_router(schema_router)
13
+ brilliance_admin_router.include_router(schema_table)
14
+ brilliance_admin_router.include_router(schema_auth)
15
+ brilliance_admin_router.include_router(schema_autocomplete)
16
+ brilliance_admin_router.include_router(schema_graphs)
17
+ brilliance_admin_router.include_router(schema_settings)
18
+ brilliance_admin_router.include_router(schema_index)
@@ -1,6 +1,6 @@
1
1
  from fastapi import HTTPException
2
2
 
3
- from admin_panel.auth import AdminAuthentication
3
+ from brilliance_admin.auth import AdminAuthentication
4
4
 
5
5
 
6
6
  async def get_user(request):
@@ -1,10 +1,10 @@
1
1
  from fastapi import APIRouter, Request
2
2
  from fastapi.responses import JSONResponse
3
3
 
4
- from admin_panel.auth import AdminAuthentication, AuthData, AuthResult
5
- from admin_panel.exceptions import AdminAPIException, APIError
6
- from admin_panel.schema.admin_schema import AdminSchema
7
- from admin_panel.translations import LanguageManager
4
+ from brilliance_admin.auth import AdminAuthentication, AuthData, AuthResult
5
+ from brilliance_admin.exceptions import AdminAPIException, APIError
6
+ from brilliance_admin.schema.admin_schema import AdminSchema
7
+ from brilliance_admin.translations import LanguageContext
8
8
 
9
9
  router = APIRouter(prefix="/auth", tags=["Auth"])
10
10
 
@@ -17,8 +17,8 @@ async def login(request: Request, auth_data: AuthData) -> AuthResult:
17
17
  schema: AdminSchema = request.app.state.schema
18
18
 
19
19
  language_slug = request.headers.get('Accept-Language')
20
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
21
- context = {'language_manager': language_manager}
20
+ language_context: LanguageContext = schema.get_language_context(language_slug)
21
+ context = {'language_context': language_context}
22
22
 
23
23
  auth: AdminAuthentication = schema.auth
24
24
  try:
@@ -1,12 +1,12 @@
1
1
  from fastapi import APIRouter, Request
2
2
  from fastapi.responses import JSONResponse
3
3
 
4
- from admin_panel.api.utils import get_category
5
- from admin_panel.exceptions import AdminAPIException
6
- from admin_panel.schema.admin_schema import AdminSchema
7
- from admin_panel.schema.table.table_models import AutocompleteData, AutocompleteResult
8
- from admin_panel.translations import LanguageManager
9
- from admin_panel.utils import get_logger
4
+ from brilliance_admin.api.utils import get_category
5
+ from brilliance_admin.exceptions import AdminAPIException
6
+ from brilliance_admin.schema.admin_schema import AdminSchema
7
+ from brilliance_admin.schema.table.table_models import AutocompleteData, AutocompleteResult
8
+ from brilliance_admin.translations import LanguageContext
9
+ from brilliance_admin.utils import get_logger
10
10
 
11
11
  router = APIRouter(prefix="/autocomplete", tags=["Autocomplete"])
12
12
 
@@ -19,11 +19,11 @@ async def autocomplete(request: Request, group: str, category: str, data: Autoco
19
19
  schema_category, user = await get_category(request, group, category)
20
20
 
21
21
  language_slug = request.headers.get('Accept-Language')
22
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
23
- context = {'language_manager': language_manager}
22
+ language_context: LanguageContext = schema.get_language_context(language_slug)
23
+ context = {'language_context': language_context}
24
24
 
25
25
  try:
26
- result: AutocompleteResult = await schema_category.autocomplete(data, user, language_manager)
26
+ result: AutocompleteResult = await schema_category.autocomplete(data, user, language_context)
27
27
  except AdminAPIException as e:
28
28
  return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
29
29
  except Exception as e:
@@ -1,12 +1,12 @@
1
1
  from fastapi import APIRouter, Request
2
2
  from fastapi.responses import JSONResponse
3
3
 
4
- from admin_panel.api.utils import get_category
5
- from admin_panel.exceptions import AdminAPIException
6
- from admin_panel.schema.admin_schema import AdminSchema
7
- from admin_panel.schema.graphs.category_graphs import CategoryGraphs, GraphData, GraphsDataResult
8
- from admin_panel.translations import LanguageManager
9
- from admin_panel.utils import get_logger
4
+ from brilliance_admin.api.utils import get_category
5
+ from brilliance_admin.exceptions import AdminAPIException
6
+ from brilliance_admin.schema.admin_schema import AdminSchema
7
+ from brilliance_admin.schema.graphs.category_graphs import CategoryGraphs, GraphData, GraphsDataResult
8
+ from brilliance_admin.translations import LanguageContext
9
+ from brilliance_admin.utils import get_logger
10
10
 
11
11
  router = APIRouter(prefix="/graph", tags=["Category - Graph"])
12
12
 
@@ -21,8 +21,8 @@ async def graph_data(request: Request, group: str, category: str, data: GraphDat
21
21
  result: GraphsDataResult = await schema_category.get_data(data, user)
22
22
 
23
23
  language_slug = request.headers.get('Accept-Language')
24
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
25
- context = {'language_manager': language_manager}
24
+ language_context: LanguageContext = schema.get_language_context(language_slug)
25
+ context = {'language_context': language_context}
26
26
 
27
27
  try:
28
28
  return JSONResponse(result.model_dump(mode='json', context=context))
@@ -1,15 +1,17 @@
1
+ from pathlib import PurePosixPath
2
+
1
3
  from fastapi import APIRouter, HTTPException, Request
2
4
  from fastapi.responses import HTMLResponse
3
5
  from fastapi.templating import Jinja2Templates
4
6
  from jinja2 import Environment, PackageLoader, select_autoescape
5
7
 
6
- from admin_panel.schema import AdminSchema
8
+ from brilliance_admin.schema import AdminSchema
7
9
 
8
10
  router = APIRouter()
9
11
 
10
12
  templates = Jinja2Templates(
11
13
  env=Environment(
12
- loader=PackageLoader("admin_panel", "templates"),
14
+ loader=PackageLoader("brilliance_admin", "templates"),
13
15
  autoescape=select_autoescape(["html", "xml"]),
14
16
  )
15
17
  )
@@ -25,8 +27,13 @@ async def admin_index(request: Request, rest_of_path: str):
25
27
  The request responds with a pre-rendered SPA served as an HTML page.
26
28
  '''
27
29
 
28
- path = "/" + rest_of_path
29
- if path in EXACT_BLOCK or path.startswith(PREFIX_BLOCK):
30
+ path = PurePosixPath('/' + rest_of_path)
31
+
32
+ if '..' in path.parts:
33
+ raise HTTPException(status_code=404)
34
+
35
+ path_str = str(path)
36
+ if path_str in EXACT_BLOCK or path_str.startswith(PREFIX_BLOCK):
30
37
  raise HTTPException(status_code=404)
31
38
 
32
39
  schema: AdminSchema = request.app.state.schema
@@ -1,9 +1,9 @@
1
1
  from fastapi import APIRouter, Request
2
2
  from fastapi.responses import JSONResponse
3
3
 
4
- from admin_panel.auth import AdminAuthentication
5
- from admin_panel.exceptions import AdminAPIException, APIError
6
- from admin_panel.schema import AdminSchema, AdminSchemaData
4
+ from brilliance_admin.auth import AdminAuthentication
5
+ from brilliance_admin.exceptions import AdminAPIException, APIError
6
+ from brilliance_admin.schema import AdminSchema, AdminSchemaData
7
7
 
8
8
  router = APIRouter(prefix="/schema", tags=["Main admin schema"])
9
9
 
@@ -1,9 +1,9 @@
1
1
  from fastapi import APIRouter, Request
2
2
  from fastapi.responses import JSONResponse
3
3
 
4
- from admin_panel.exceptions import AdminAPIException, APIError
5
- from admin_panel.schema.admin_schema import AdminSchema, AdminSettingsData
6
- from admin_panel.translations import LanguageManager
4
+ from brilliance_admin.exceptions import AdminAPIException, APIError
5
+ from brilliance_admin.schema.admin_schema import AdminSchema, AdminSettingsData
6
+ from brilliance_admin.translations import LanguageContext
7
7
 
8
8
  router = APIRouter(tags=["Settings"])
9
9
 
@@ -19,8 +19,8 @@ async def get_settings(request: Request) -> AdminSettingsData:
19
19
  schema: AdminSchema = request.app.state.schema
20
20
 
21
21
  language_slug = request.headers.get('Accept-Language')
22
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
23
- context = {'language_manager': language_manager}
22
+ language_context: LanguageContext = schema.get_language_context(language_slug)
23
+ context = {'language_context': language_context}
24
24
 
25
25
  try:
26
26
  admin_settings = await schema.get_settings(request)
@@ -3,14 +3,15 @@ from typing import Any
3
3
  from fastapi import APIRouter, HTTPException, Request
4
4
  from fastapi.responses import JSONResponse
5
5
 
6
- from admin_panel.api.utils import get_category
7
- from admin_panel.exceptions import AdminAPIException, APIError
8
- from admin_panel.schema import AdminSchema
9
- from admin_panel.schema.table.admin_action import ActionData, ActionResult
10
- from admin_panel.schema.table.category_table import CategoryTable
11
- from admin_panel.schema.table.table_models import CreateResult, ListData, RetrieveResult, TableListResult, UpdateResult
12
- from admin_panel.translations import LanguageManager
13
- from admin_panel.utils import get_logger
6
+ from brilliance_admin.api.utils import get_category
7
+ from brilliance_admin.exceptions import AdminAPIException, APIError
8
+ from brilliance_admin.schema import AdminSchema
9
+ from brilliance_admin.schema.table.admin_action import ActionData, ActionResult
10
+ from brilliance_admin.schema.table.category_table import CategoryTable
11
+ from brilliance_admin.schema.table.table_models import (
12
+ CreateResult, ListData, RetrieveResult, TableListResult, UpdateResult)
13
+ from brilliance_admin.translations import LanguageContext
14
+ from brilliance_admin.utils import get_logger
14
15
 
15
16
  router = APIRouter(prefix="/table", tags=["Category - Table"])
16
17
 
@@ -25,11 +26,11 @@ async def table_list(request: Request, group: str, category: str, list_data: Lis
25
26
  schema_category, user = await get_category(request, group, category, check_type=CategoryTable)
26
27
 
27
28
  language_slug = request.headers.get('Accept-Language')
28
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
29
- context = {'language_manager': language_manager}
29
+ language_context: LanguageContext = schema.get_language_context(language_slug)
30
+ context = {'language_context': language_context}
30
31
 
31
32
  try:
32
- result: TableListResult = await schema_category.get_list(list_data, user, language_manager)
33
+ result: TableListResult = await schema_category.get_list(list_data, user, language_context)
33
34
  except AdminAPIException as e:
34
35
  return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
35
36
 
@@ -49,11 +50,11 @@ async def table_retrieve(request: Request, group: str, category: str, pk: Any) -
49
50
  raise HTTPException(status_code=404, detail=f"Category {group}.{category} is not allowed for retrive")
50
51
 
51
52
  language_slug = request.headers.get('Accept-Language')
52
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
53
- context = {'language_manager': language_manager}
53
+ language_context: LanguageContext = schema.get_language_context(language_slug)
54
+ context = {'language_context': language_context}
54
55
 
55
56
  try:
56
- result: RetrieveResult = await schema_category.retrieve(pk, user, language_manager)
57
+ result: RetrieveResult = await schema_category.retrieve(pk, user, language_context)
57
58
  except AdminAPIException as e:
58
59
  return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
59
60
 
@@ -72,11 +73,11 @@ async def table_create(request: Request, group: str, category: str) -> CreateRes
72
73
  raise HTTPException(status_code=404, detail=f"Category {group}.{category} is not allowed for create")
73
74
 
74
75
  language_slug = request.headers.get('Accept-Language')
75
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
76
- context = {'language_manager': language_manager}
76
+ language_context: LanguageContext = schema.get_language_context(language_slug)
77
+ context = {'language_context': language_context}
77
78
 
78
79
  try:
79
- result: CreateResult = await schema_category.create(await request.json(), user, language_manager)
80
+ result: CreateResult = await schema_category.create(await request.json(), user, language_context)
80
81
  except AdminAPIException as e:
81
82
  return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
82
83
 
@@ -95,11 +96,11 @@ async def table_update(request: Request, group: str, category: str, pk: Any) ->
95
96
  raise HTTPException(status_code=404, detail=f"Category {group}.{category} is not allowed for update")
96
97
 
97
98
  language_slug = request.headers.get('Accept-Language')
98
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
99
- context = {'language_manager': language_manager}
99
+ language_context: LanguageContext = schema.get_language_context(language_slug)
100
+ context = {'language_context': language_context}
100
101
 
101
102
  try:
102
- result: UpdateResult = await schema_category.update(pk, await request.json(), user, language_manager)
103
+ result: UpdateResult = await schema_category.update(pk, await request.json(), user, language_context)
103
104
  except AdminAPIException as e:
104
105
  return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
105
106
 
@@ -122,13 +123,13 @@ async def table_action(
122
123
  schema_category, user = await get_category(request, group, category, check_type=CategoryTable)
123
124
 
124
125
  language_slug = request.headers.get('Accept-Language')
125
- language_manager: LanguageManager = schema.get_language_manager(language_slug)
126
- context = {'language_manager': language_manager}
126
+ language_context: LanguageContext = schema.get_language_context(language_slug)
127
+ context = {'language_context': language_context}
127
128
 
128
129
  try:
129
130
  # pylint: disable=protected-access
130
131
  result: ActionResult = await schema_category._perform_action(
131
- request, action, action_data, language_manager, user,
132
+ request, action, action_data, language_context, user,
132
133
  )
133
134
  except AdminAPIException as e:
134
135
  return JSONResponse(e.get_error().model_dump(mode='json', context=context), status_code=e.status_code)
@@ -2,7 +2,7 @@ import abc
2
2
 
3
3
  from pydantic import BaseModel
4
4
  from pydantic.dataclasses import dataclass
5
- from admin_panel.utils import DataclassBase
5
+ from brilliance_admin.utils import DataclassBase
6
6
 
7
7
 
8
8
  @dataclass
@@ -3,14 +3,14 @@ from typing import Dict
3
3
  from pydantic import Field
4
4
  from pydantic.dataclasses import dataclass
5
5
 
6
- from admin_panel.translations import TranslateText
7
- from admin_panel.utils import DataclassBase
6
+ from brilliance_admin.utils import DataclassBase, SupportsStr
8
7
 
9
8
 
10
9
  @dataclass
11
10
  class FieldError(DataclassBase, Exception):
12
- message: str | TranslateText = None
11
+ message: SupportsStr = None
13
12
  code: str | None = None
13
+ field_slug: str | None = None
14
14
 
15
15
  def __post_init__(self):
16
16
  if not self.message and not self.code:
@@ -20,7 +20,7 @@ class FieldError(DataclassBase, Exception):
20
20
 
21
21
  @dataclass
22
22
  class APIError(DataclassBase):
23
- message: str | TranslateText | None = None
23
+ message: SupportsStr | None = None
24
24
  code: str | None = None
25
25
  field_errors: Dict[str, FieldError] | None = None
26
26
 
@@ -1,5 +1,6 @@
1
1
  # pylint: disable=wildcard-import, unused-wildcard-import, unused-import
2
2
  # flake8: noqa: F405
3
+ from .fields import SQLAlchemyRelatedField
3
4
  from .auth import SQLAlchemyJWTAdminAuthentication
4
5
  from .autocomplete import SQLAlchemyAdminAutocompleteMixin
5
6
  from .fields_schema import SQLAlchemyFieldsSchema