django-admin-modern-view 0.2.1__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.
- django_admin_modern_view-0.2.1/CHANGELOG.md +13 -0
- django_admin_modern_view-0.2.1/LICENSE +21 -0
- django_admin_modern_view-0.2.1/MANIFEST.in +5 -0
- django_admin_modern_view-0.2.1/PKG-INFO +192 -0
- django_admin_modern_view-0.2.1/README.md +159 -0
- django_admin_modern_view-0.2.1/pyproject.toml +61 -0
- django_admin_modern_view-0.2.1/setup.cfg +4 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/__init__.py +1 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/apps.py +10 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/checks.py +55 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/services/__init__.py +0 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/services/command_registry.py +78 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/services/search.py +101 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/css/base.css +69 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/css/command-palette.css +151 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/css/forms.css +189 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/css/layout.css +315 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/css/sidebar.css +412 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/css/tables.css +402 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/css/utilities.css +236 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/css/variables.css +208 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/app.js +72 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/command-palette.js +226 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/dashboard.js +87 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/forms.js +0 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/global-search.js +29 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/notifications.js +58 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/shortcuts.js +76 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/sidebar.js +158 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/table.js +234 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/static/django_admin_modern_view/js/utils.js +105 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/templates/admin/base_site.html +114 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/templates/admin/index.html +58 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/templatetags/__init__.py +0 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/templatetags/django_admin_modern_view_tags.py +36 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/urls.py +10 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view/views.py +18 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view.egg-info/PKG-INFO +192 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view.egg-info/SOURCES.txt +44 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view.egg-info/dependency_links.txt +1 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view.egg-info/requires.txt +5 -0
- django_admin_modern_view-0.2.1/src/django_admin_modern_view.egg-info/top_level.txt +1 -0
- django_admin_modern_view-0.2.1/tests/test_checks.py +35 -0
- django_admin_modern_view-0.2.1/tests/test_command_registry.py +46 -0
- django_admin_modern_view-0.2.1/tests/test_search.py +47 -0
- django_admin_modern_view-0.2.1/tests/test_views.py +38 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.1.0 — Initial release
|
|
4
|
+
|
|
5
|
+
- Modern application shell for `django.contrib.admin`: sticky topbar, collapsible/searchable sidebar with per-app collapse, light/dark theme (built on Django's own theme toggle).
|
|
6
|
+
- Command palette (`Ctrl+K`): fuzzy navigation + create commands, auto-derived from the admin site, plus a `register_command()` API for custom entries.
|
|
7
|
+
- Global search: searches every `ModelAdmin` with `search_fields` (auto-registered) or explicitly via `register_global_search()`; permission-aware.
|
|
8
|
+
- Keyboard shortcuts: `Ctrl+K` search, `Ctrl+S` / `Ctrl+Shift+S` save, `J`/`K`/`Enter`/`Space` row navigation on change lists, `?` shortcut help, `Esc` closes the active overlay.
|
|
9
|
+
- Enhanced change list: sticky header, keyboard row navigation, a Frappe-style "Filters" dropdown built from your existing `list_filter` configuration.
|
|
10
|
+
- Enhanced change form: sticky save bar with a dirty-state indicator and an unsaved-changes warning on navigation.
|
|
11
|
+
- Dashboard: per-model stat cards and collapsible per-app sections with model counts, replacing the plain app-list index.
|
|
12
|
+
- `django_admin_modern_view.W001` system check: warns if the app is misordered relative to `django.contrib.admin` in `INSTALLED_APPS`.
|
|
13
|
+
- Zero changes required to existing `ModelAdmin` classes — everything layers on top of `list_display`, `list_filter`, `search_fields`, `fieldsets`, `inlines`, `actions`, and permissions as already configured.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Hitesh
|
|
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 NONINFRINGEMENT. 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,192 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-admin-modern-view
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: A modern, keyboard-first UI layer for Django's built-in admin — command palette, global search, dashboard, and more, on top of your existing ModelAdmin config.
|
|
5
|
+
Author: Hitesh
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/HItzz07/Django-adminkit
|
|
8
|
+
Project-URL: Repository, https://github.com/HItzz07/Django-adminkit
|
|
9
|
+
Project-URL: Issues, https://github.com/HItzz07/Django-adminkit/issues
|
|
10
|
+
Keywords: django,admin,ui,command-palette,dashboard
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Environment :: Web Environment
|
|
13
|
+
Classifier: Framework :: Django
|
|
14
|
+
Classifier: Framework :: Django :: 5.1
|
|
15
|
+
Classifier: Framework :: Django :: 5.2
|
|
16
|
+
Classifier: Intended Audience :: Developers
|
|
17
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
18
|
+
Classifier: Operating System :: OS Independent
|
|
19
|
+
Classifier: Programming Language :: Python :: 3
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
23
|
+
Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
|
|
24
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
|
+
Requires-Python: >=3.10
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: Django<6.0,>=5.1
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-django>=4.7; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# django-admin-modern-view
|
|
35
|
+
|
|
36
|
+
A modern, keyboard-first UI layer for Django's built-in admin. Drop it into
|
|
37
|
+
`INSTALLED_APPS`, keep your existing `ModelAdmin` classes exactly as they
|
|
38
|
+
are, and the admin gets a command palette, global search, a real dashboard,
|
|
39
|
+
and a reskinned shell — without giving up anything Django's admin already
|
|
40
|
+
does for you (permissions, `list_filter`, inlines, actions, forms).
|
|
41
|
+
|
|
42
|
+
This is **not** a fork of `django.contrib.admin` and it does not replace it.
|
|
43
|
+
It ships two small template overrides (the shell + the dashboard) and pure
|
|
44
|
+
CSS/JS progressive enhancement on top of the admin's existing, stable DOM
|
|
45
|
+
(`#result_list`, `#changelist-filter`, `.submit-row`, `#nav-sidebar`, …).
|
|
46
|
+
Every page Django's admin can render, it can still render with this
|
|
47
|
+
installed — worst case you lose the extra chrome, you never lose function.
|
|
48
|
+
|
|
49
|
+
## Features
|
|
50
|
+
|
|
51
|
+
- **Command palette** (`Ctrl+K`) — fuzzy-search navigation and "create"
|
|
52
|
+
commands, generated from your admin site's registered models, plus a
|
|
53
|
+
`register_command()` API for anything custom.
|
|
54
|
+
- **Global search** — searches every `ModelAdmin` that already defines
|
|
55
|
+
`search_fields` (zero config), permission-checked per model.
|
|
56
|
+
- **Keyboard shortcuts** — `Ctrl+S`/`Ctrl+Shift+S` save, `J`/`K`/`Enter`/
|
|
57
|
+
`Space` to navigate and select change-list rows, `?` for a shortcut
|
|
58
|
+
cheat sheet, `Esc` closes whatever overlay is open.
|
|
59
|
+
- **Enhanced change list** — sticky header, keyboard row navigation, and a
|
|
60
|
+
dropdown "Filters" panel built from your existing `list_filter`.
|
|
61
|
+
- **Enhanced change form** — sticky save bar, dirty-state indicator,
|
|
62
|
+
unsaved-changes warning before navigating away.
|
|
63
|
+
- **Dashboard** — per-model stat cards and collapsible per-app sections
|
|
64
|
+
(with model counts) in place of the plain default app list.
|
|
65
|
+
- **Light/dark theme** — reskins Django's own built-in theme toggle; no
|
|
66
|
+
separate dark-mode system to maintain.
|
|
67
|
+
- A system check that catches the #1 setup mistake (see below) instead of
|
|
68
|
+
failing silently.
|
|
69
|
+
|
|
70
|
+
## Requirements
|
|
71
|
+
|
|
72
|
+
- Django 5.1 or newer (uses the admin's built-in dark-mode theme toggle and
|
|
73
|
+
collapsible sidebar, both introduced in 5.1).
|
|
74
|
+
- Python 3.10+.
|
|
75
|
+
|
|
76
|
+
## Install
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
pip install django-admin-modern-view
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Or, until it's published, install straight from GitHub:
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
pip install git+https://github.com/HItzz07/Django-adminkit.git
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
For local development against this repo:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install -e /path/to/django-admin-modern-view
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Quickstart
|
|
95
|
+
|
|
96
|
+
1. Add it to `INSTALLED_APPS`, **before** `django.contrib.admin` — Django's
|
|
97
|
+
template loader resolves `admin/*.html` overrides by walking
|
|
98
|
+
`INSTALLED_APPS` in order and using the first match:
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
INSTALLED_APPS = [
|
|
102
|
+
"django_admin_modern_view", # must come before django.contrib.admin
|
|
103
|
+
|
|
104
|
+
"django.contrib.admin",
|
|
105
|
+
"django.contrib.auth",
|
|
106
|
+
"django.contrib.contenttypes",
|
|
107
|
+
"django.contrib.sessions",
|
|
108
|
+
"django.contrib.messages",
|
|
109
|
+
"django.contrib.staticfiles",
|
|
110
|
+
|
|
111
|
+
# your apps...
|
|
112
|
+
]
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
2. Wire its URLs in front of the admin's own (it only adds two small JSON
|
|
116
|
+
endpoints under `admin/`, both `staff_member_required`):
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from django.contrib import admin
|
|
120
|
+
from django.urls import include, path
|
|
121
|
+
|
|
122
|
+
urlpatterns = [
|
|
123
|
+
path("admin/", include("django_admin_modern_view.urls")),
|
|
124
|
+
path("admin/", admin.site.urls),
|
|
125
|
+
]
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
3. Run the server. That's it — no changes to your `ModelAdmin` classes are
|
|
129
|
+
required. If something looks unstyled, run `python manage.py check`;
|
|
130
|
+
the bundled system check (`django_admin_modern_view.W001`) will tell you if the
|
|
131
|
+
`INSTALLED_APPS` order is the problem.
|
|
132
|
+
|
|
133
|
+
## Configuration
|
|
134
|
+
|
|
135
|
+
### Custom command palette entries
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
# anywhere that runs at import time, e.g. your app's apps.py ready()
|
|
139
|
+
from django_admin_modern_view.services.command_registry import register_command
|
|
140
|
+
|
|
141
|
+
register_command(
|
|
142
|
+
id="reindex_search",
|
|
143
|
+
label="Rebuild search index",
|
|
144
|
+
category="Actions",
|
|
145
|
+
url="/admin/tools/reindex/",
|
|
146
|
+
icon="refresh",
|
|
147
|
+
)
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Custom global search sources
|
|
151
|
+
|
|
152
|
+
Any `ModelAdmin` with `search_fields` is picked up automatically. To search
|
|
153
|
+
a model that isn't registered with the admin, or to use different fields
|
|
154
|
+
than the admin search box does:
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
from django_admin_modern_view.services.search import register_global_search
|
|
158
|
+
from myapp.models import Order
|
|
159
|
+
|
|
160
|
+
register_global_search(Order, fields=["reference", "customer__email"], label="Orders")
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
`search_fields` prefixes work the same way they do for `ModelAdmin`:
|
|
164
|
+
`^field` (starts-with), `=field` (exact), `@field` (full-text), plain
|
|
165
|
+
`field` (contains).
|
|
166
|
+
|
|
167
|
+
## How it stays compatible
|
|
168
|
+
|
|
169
|
+
This package only overrides two templates: `admin/base_site.html` (the
|
|
170
|
+
shell every admin page extends) and `admin/index.html` (the dashboard).
|
|
171
|
+
Change lists, change forms, inlines, filters, and actions are all still
|
|
172
|
+
Django's own templates — this package only attaches CSS and progressive-
|
|
173
|
+
enhancement JS to their existing, stable element IDs. That means:
|
|
174
|
+
|
|
175
|
+
- Every `ModelAdmin` option (`list_display`, `list_filter`, `search_fields`,
|
|
176
|
+
`fieldsets`, `inlines`, `actions`, permissions) keeps working exactly as
|
|
177
|
+
configured.
|
|
178
|
+
- The admin still works with JavaScript disabled — the extra chrome (command
|
|
179
|
+
palette, dirty-state indicator, keyboard nav) is progressive enhancement,
|
|
180
|
+
not a requirement.
|
|
181
|
+
- No monkey-patching of `django.contrib.admin` internals.
|
|
182
|
+
|
|
183
|
+
## Development
|
|
184
|
+
|
|
185
|
+
```bash
|
|
186
|
+
pip install -e ".[dev]"
|
|
187
|
+
pytest
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## License
|
|
191
|
+
|
|
192
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# django-admin-modern-view
|
|
2
|
+
|
|
3
|
+
A modern, keyboard-first UI layer for Django's built-in admin. Drop it into
|
|
4
|
+
`INSTALLED_APPS`, keep your existing `ModelAdmin` classes exactly as they
|
|
5
|
+
are, and the admin gets a command palette, global search, a real dashboard,
|
|
6
|
+
and a reskinned shell — without giving up anything Django's admin already
|
|
7
|
+
does for you (permissions, `list_filter`, inlines, actions, forms).
|
|
8
|
+
|
|
9
|
+
This is **not** a fork of `django.contrib.admin` and it does not replace it.
|
|
10
|
+
It ships two small template overrides (the shell + the dashboard) and pure
|
|
11
|
+
CSS/JS progressive enhancement on top of the admin's existing, stable DOM
|
|
12
|
+
(`#result_list`, `#changelist-filter`, `.submit-row`, `#nav-sidebar`, …).
|
|
13
|
+
Every page Django's admin can render, it can still render with this
|
|
14
|
+
installed — worst case you lose the extra chrome, you never lose function.
|
|
15
|
+
|
|
16
|
+
## Features
|
|
17
|
+
|
|
18
|
+
- **Command palette** (`Ctrl+K`) — fuzzy-search navigation and "create"
|
|
19
|
+
commands, generated from your admin site's registered models, plus a
|
|
20
|
+
`register_command()` API for anything custom.
|
|
21
|
+
- **Global search** — searches every `ModelAdmin` that already defines
|
|
22
|
+
`search_fields` (zero config), permission-checked per model.
|
|
23
|
+
- **Keyboard shortcuts** — `Ctrl+S`/`Ctrl+Shift+S` save, `J`/`K`/`Enter`/
|
|
24
|
+
`Space` to navigate and select change-list rows, `?` for a shortcut
|
|
25
|
+
cheat sheet, `Esc` closes whatever overlay is open.
|
|
26
|
+
- **Enhanced change list** — sticky header, keyboard row navigation, and a
|
|
27
|
+
dropdown "Filters" panel built from your existing `list_filter`.
|
|
28
|
+
- **Enhanced change form** — sticky save bar, dirty-state indicator,
|
|
29
|
+
unsaved-changes warning before navigating away.
|
|
30
|
+
- **Dashboard** — per-model stat cards and collapsible per-app sections
|
|
31
|
+
(with model counts) in place of the plain default app list.
|
|
32
|
+
- **Light/dark theme** — reskins Django's own built-in theme toggle; no
|
|
33
|
+
separate dark-mode system to maintain.
|
|
34
|
+
- A system check that catches the #1 setup mistake (see below) instead of
|
|
35
|
+
failing silently.
|
|
36
|
+
|
|
37
|
+
## Requirements
|
|
38
|
+
|
|
39
|
+
- Django 5.1 or newer (uses the admin's built-in dark-mode theme toggle and
|
|
40
|
+
collapsible sidebar, both introduced in 5.1).
|
|
41
|
+
- Python 3.10+.
|
|
42
|
+
|
|
43
|
+
## Install
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
pip install django-admin-modern-view
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Or, until it's published, install straight from GitHub:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install git+https://github.com/HItzz07/Django-adminkit.git
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
For local development against this repo:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
pip install -e /path/to/django-admin-modern-view
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Quickstart
|
|
62
|
+
|
|
63
|
+
1. Add it to `INSTALLED_APPS`, **before** `django.contrib.admin` — Django's
|
|
64
|
+
template loader resolves `admin/*.html` overrides by walking
|
|
65
|
+
`INSTALLED_APPS` in order and using the first match:
|
|
66
|
+
|
|
67
|
+
```python
|
|
68
|
+
INSTALLED_APPS = [
|
|
69
|
+
"django_admin_modern_view", # must come before django.contrib.admin
|
|
70
|
+
|
|
71
|
+
"django.contrib.admin",
|
|
72
|
+
"django.contrib.auth",
|
|
73
|
+
"django.contrib.contenttypes",
|
|
74
|
+
"django.contrib.sessions",
|
|
75
|
+
"django.contrib.messages",
|
|
76
|
+
"django.contrib.staticfiles",
|
|
77
|
+
|
|
78
|
+
# your apps...
|
|
79
|
+
]
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
2. Wire its URLs in front of the admin's own (it only adds two small JSON
|
|
83
|
+
endpoints under `admin/`, both `staff_member_required`):
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
from django.contrib import admin
|
|
87
|
+
from django.urls import include, path
|
|
88
|
+
|
|
89
|
+
urlpatterns = [
|
|
90
|
+
path("admin/", include("django_admin_modern_view.urls")),
|
|
91
|
+
path("admin/", admin.site.urls),
|
|
92
|
+
]
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
3. Run the server. That's it — no changes to your `ModelAdmin` classes are
|
|
96
|
+
required. If something looks unstyled, run `python manage.py check`;
|
|
97
|
+
the bundled system check (`django_admin_modern_view.W001`) will tell you if the
|
|
98
|
+
`INSTALLED_APPS` order is the problem.
|
|
99
|
+
|
|
100
|
+
## Configuration
|
|
101
|
+
|
|
102
|
+
### Custom command palette entries
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# anywhere that runs at import time, e.g. your app's apps.py ready()
|
|
106
|
+
from django_admin_modern_view.services.command_registry import register_command
|
|
107
|
+
|
|
108
|
+
register_command(
|
|
109
|
+
id="reindex_search",
|
|
110
|
+
label="Rebuild search index",
|
|
111
|
+
category="Actions",
|
|
112
|
+
url="/admin/tools/reindex/",
|
|
113
|
+
icon="refresh",
|
|
114
|
+
)
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Custom global search sources
|
|
118
|
+
|
|
119
|
+
Any `ModelAdmin` with `search_fields` is picked up automatically. To search
|
|
120
|
+
a model that isn't registered with the admin, or to use different fields
|
|
121
|
+
than the admin search box does:
|
|
122
|
+
|
|
123
|
+
```python
|
|
124
|
+
from django_admin_modern_view.services.search import register_global_search
|
|
125
|
+
from myapp.models import Order
|
|
126
|
+
|
|
127
|
+
register_global_search(Order, fields=["reference", "customer__email"], label="Orders")
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
`search_fields` prefixes work the same way they do for `ModelAdmin`:
|
|
131
|
+
`^field` (starts-with), `=field` (exact), `@field` (full-text), plain
|
|
132
|
+
`field` (contains).
|
|
133
|
+
|
|
134
|
+
## How it stays compatible
|
|
135
|
+
|
|
136
|
+
This package only overrides two templates: `admin/base_site.html` (the
|
|
137
|
+
shell every admin page extends) and `admin/index.html` (the dashboard).
|
|
138
|
+
Change lists, change forms, inlines, filters, and actions are all still
|
|
139
|
+
Django's own templates — this package only attaches CSS and progressive-
|
|
140
|
+
enhancement JS to their existing, stable element IDs. That means:
|
|
141
|
+
|
|
142
|
+
- Every `ModelAdmin` option (`list_display`, `list_filter`, `search_fields`,
|
|
143
|
+
`fieldsets`, `inlines`, `actions`, permissions) keeps working exactly as
|
|
144
|
+
configured.
|
|
145
|
+
- The admin still works with JavaScript disabled — the extra chrome (command
|
|
146
|
+
palette, dirty-state indicator, keyboard nav) is progressive enhancement,
|
|
147
|
+
not a requirement.
|
|
148
|
+
- No monkey-patching of `django.contrib.admin` internals.
|
|
149
|
+
|
|
150
|
+
## Development
|
|
151
|
+
|
|
152
|
+
```bash
|
|
153
|
+
pip install -e ".[dev]"
|
|
154
|
+
pytest
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT — see [LICENSE](LICENSE).
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "django-admin-modern-view"
|
|
7
|
+
version = "0.2.1"
|
|
8
|
+
description = "A modern, keyboard-first UI layer for Django's built-in admin — command palette, global search, dashboard, and more, on top of your existing ModelAdmin config."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = { text = "MIT" }
|
|
12
|
+
authors = [
|
|
13
|
+
{ name = "Hitesh" },
|
|
14
|
+
]
|
|
15
|
+
keywords = ["django", "admin", "ui", "command-palette", "dashboard"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Environment :: Web Environment",
|
|
19
|
+
"Framework :: Django",
|
|
20
|
+
"Framework :: Django :: 5.1",
|
|
21
|
+
"Framework :: Django :: 5.2",
|
|
22
|
+
"Intended Audience :: Developers",
|
|
23
|
+
"License :: OSI Approved :: MIT License",
|
|
24
|
+
"Operating System :: OS Independent",
|
|
25
|
+
"Programming Language :: Python :: 3",
|
|
26
|
+
"Programming Language :: Python :: 3.10",
|
|
27
|
+
"Programming Language :: Python :: 3.11",
|
|
28
|
+
"Programming Language :: Python :: 3.12",
|
|
29
|
+
"Topic :: Internet :: WWW/HTTP :: Dynamic Content",
|
|
30
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
31
|
+
]
|
|
32
|
+
dependencies = [
|
|
33
|
+
"Django>=5.1,<6.0",
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
[project.urls]
|
|
37
|
+
Homepage = "https://github.com/HItzz07/Django-adminkit"
|
|
38
|
+
Repository = "https://github.com/HItzz07/Django-adminkit"
|
|
39
|
+
Issues = "https://github.com/HItzz07/Django-adminkit/issues"
|
|
40
|
+
|
|
41
|
+
[project.optional-dependencies]
|
|
42
|
+
dev = [
|
|
43
|
+
"pytest>=7.4",
|
|
44
|
+
"pytest-django>=4.7",
|
|
45
|
+
]
|
|
46
|
+
|
|
47
|
+
[tool.setuptools.packages.find]
|
|
48
|
+
where = ["src"]
|
|
49
|
+
include = ["django_admin_modern_view*"]
|
|
50
|
+
|
|
51
|
+
[tool.setuptools.package-data]
|
|
52
|
+
django_admin_modern_view = [
|
|
53
|
+
"templates/admin/*.html",
|
|
54
|
+
"static/django_admin_modern_view/css/*.css",
|
|
55
|
+
"static/django_admin_modern_view/js/*.js",
|
|
56
|
+
]
|
|
57
|
+
|
|
58
|
+
[tool.pytest.ini_options]
|
|
59
|
+
DJANGO_SETTINGS_MODULE = "tests.settings"
|
|
60
|
+
python_files = ["test_*.py"]
|
|
61
|
+
pythonpath = ["."]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "0.2.1"
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
from django.apps import AppConfig
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class DjangoAdminModernViewConfig(AppConfig):
|
|
5
|
+
default_auto_field = "django.db.models.BigAutoField"
|
|
6
|
+
name = "django_admin_modern_view"
|
|
7
|
+
verbose_name = "Django Admin Modern View"
|
|
8
|
+
|
|
9
|
+
def ready(self):
|
|
10
|
+
from . import checks # noqa: F401 (registers Django system checks)
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"""Django system checks that catch the one setup mistake this package
|
|
2
|
+
can't work around: app ordering.
|
|
3
|
+
|
|
4
|
+
Django's app_dirs template loader resolves ``admin/*.html`` overrides by
|
|
5
|
+
walking INSTALLED_APPS in order and using the first match. If
|
|
6
|
+
django_admin_modern_view isn't listed before django.contrib.admin, its template
|
|
7
|
+
overrides silently lose to Django's own — the admin just looks
|
|
8
|
+
unstyled, with no error to point at why.
|
|
9
|
+
"""
|
|
10
|
+
from django.apps import apps
|
|
11
|
+
from django.conf import settings
|
|
12
|
+
from django.core.checks import Warning, register
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
@register()
|
|
16
|
+
def check_app_order(app_configs, **kwargs):
|
|
17
|
+
installed = list(settings.INSTALLED_APPS)
|
|
18
|
+
try:
|
|
19
|
+
admin_index = next(
|
|
20
|
+
i for i, name in enumerate(installed)
|
|
21
|
+
if name == "django.contrib.admin" or name.startswith("django.contrib.admin.")
|
|
22
|
+
)
|
|
23
|
+
except StopIteration:
|
|
24
|
+
return [] # django.contrib.admin isn't installed; nothing to check
|
|
25
|
+
|
|
26
|
+
try:
|
|
27
|
+
our_index = next(
|
|
28
|
+
i for i, name in enumerate(installed)
|
|
29
|
+
if name == "django_admin_modern_view" or name.startswith("django_admin_modern_view.")
|
|
30
|
+
)
|
|
31
|
+
except StopIteration:
|
|
32
|
+
our_index = None # resolved via AppConfig path instead of the bare name
|
|
33
|
+
|
|
34
|
+
if our_index is None:
|
|
35
|
+
try:
|
|
36
|
+
our_index = installed.index(apps.get_app_config("django_admin_modern_view").name)
|
|
37
|
+
except LookupError:
|
|
38
|
+
return []
|
|
39
|
+
|
|
40
|
+
if our_index > admin_index:
|
|
41
|
+
return [
|
|
42
|
+
Warning(
|
|
43
|
+
"django_admin_modern_view is listed after django.contrib.admin in "
|
|
44
|
+
"INSTALLED_APPS.",
|
|
45
|
+
hint=(
|
|
46
|
+
"Move 'django_admin_modern_view' above 'django.contrib.admin' in "
|
|
47
|
+
"INSTALLED_APPS. Django's template loader picks the "
|
|
48
|
+
"first admin/*.html it finds by app order, so this "
|
|
49
|
+
"package's overrides (topbar, command palette, dashboard) "
|
|
50
|
+
"will otherwise be silently ignored."
|
|
51
|
+
),
|
|
52
|
+
id="django_admin_modern_view.W001",
|
|
53
|
+
)
|
|
54
|
+
]
|
|
55
|
+
return []
|
|
File without changes
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Central registry for the Modern Admin command palette (Ctrl+K).
|
|
2
|
+
|
|
3
|
+
Commands are plain dicts so they serialize straight to JSON for the
|
|
4
|
+
frontend. Registered commands are merged with commands auto-derived
|
|
5
|
+
from the Django admin site (navigation + "create" actions) on every
|
|
6
|
+
request, so palette content always reflects the logged-in user's
|
|
7
|
+
permissions.
|
|
8
|
+
"""
|
|
9
|
+
from django.urls import reverse
|
|
10
|
+
|
|
11
|
+
_registered_commands = []
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def register_command(id, label, category="General", shortcut=None, url=None, icon=None, keywords=""):
|
|
15
|
+
"""Register a custom command shown in the command palette.
|
|
16
|
+
|
|
17
|
+
Example:
|
|
18
|
+
register_command(
|
|
19
|
+
id="create_user",
|
|
20
|
+
label="Create User",
|
|
21
|
+
category="Actions",
|
|
22
|
+
url="/admin/auth/user/add/",
|
|
23
|
+
)
|
|
24
|
+
"""
|
|
25
|
+
_registered_commands.append({
|
|
26
|
+
"id": id,
|
|
27
|
+
"label": label,
|
|
28
|
+
"category": category,
|
|
29
|
+
"shortcut": shortcut,
|
|
30
|
+
"url": url,
|
|
31
|
+
"icon": icon or "",
|
|
32
|
+
"keywords": keywords,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_registered_commands():
|
|
37
|
+
return list(_registered_commands)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def get_commands_for_request(request):
|
|
41
|
+
"""Build the full palette command list for the current user."""
|
|
42
|
+
from django.contrib import admin
|
|
43
|
+
|
|
44
|
+
commands = [{
|
|
45
|
+
"id": "nav:dashboard",
|
|
46
|
+
"label": "Dashboard",
|
|
47
|
+
"category": "Navigation",
|
|
48
|
+
"shortcut": None,
|
|
49
|
+
"url": reverse("admin:index"),
|
|
50
|
+
"icon": "home",
|
|
51
|
+
"keywords": "home dashboard",
|
|
52
|
+
}]
|
|
53
|
+
|
|
54
|
+
for app in admin.site.get_app_list(request):
|
|
55
|
+
for model in app["models"]:
|
|
56
|
+
if model.get("admin_url"):
|
|
57
|
+
commands.append({
|
|
58
|
+
"id": f"nav:{app['app_label']}.{model['object_name']}",
|
|
59
|
+
"label": model["name"],
|
|
60
|
+
"category": "Navigation",
|
|
61
|
+
"shortcut": None,
|
|
62
|
+
"url": model["admin_url"],
|
|
63
|
+
"icon": "list",
|
|
64
|
+
"keywords": f"{app['name']} {model['name']}",
|
|
65
|
+
})
|
|
66
|
+
if model.get("add_url"):
|
|
67
|
+
commands.append({
|
|
68
|
+
"id": f"create:{app['app_label']}.{model['object_name']}",
|
|
69
|
+
"label": f"Create {model['name']}",
|
|
70
|
+
"category": "Actions",
|
|
71
|
+
"shortcut": None,
|
|
72
|
+
"url": model["add_url"],
|
|
73
|
+
"icon": "plus",
|
|
74
|
+
"keywords": f"add new {model['name']}",
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
commands.extend(get_registered_commands())
|
|
78
|
+
return commands
|