django-boosted 0.1.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_boosted-0.1.1/LICENSE +23 -0
- django_boosted-0.1.1/PKG-INFO +138 -0
- django_boosted-0.1.1/README.md +104 -0
- django_boosted-0.1.1/pyproject.toml +83 -0
- django_boosted-0.1.1/setup.cfg +4 -0
- django_boosted-0.1.1/src/django_boosted/__init__.py +20 -0
- django_boosted-0.1.1/src/django_boosted/admin/__init__.py +5 -0
- django_boosted-0.1.1/src/django_boosted/admin/fieldsets.py +44 -0
- django_boosted-0.1.1/src/django_boosted/admin/format.py +90 -0
- django_boosted-0.1.1/src/django_boosted/admin/model.py +198 -0
- django_boosted-0.1.1/src/django_boosted/admin/tools.py +55 -0
- django_boosted-0.1.1/src/django_boosted/admin/urls.py +24 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/__init__.py +7 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/adminform.py +186 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/base.py +144 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/confirm.py +102 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/form.py +40 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/generator.py +23 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/json.py +61 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/list.py +156 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/message.py +39 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/redirect.py +82 -0
- django_boosted-0.1.1/src/django_boosted/admin/views/setup.py +54 -0
- django_boosted-0.1.1/src/django_boosted/apps.py +21 -0
- django_boosted-0.1.1/src/django_boosted/decorators.py +61 -0
- django_boosted-0.1.1/src/django_boosted/managers/__init__.py +3 -0
- django_boosted-0.1.1/src/django_boosted/managers/urls.py +122 -0
- django_boosted-0.1.1/src/django_boosted/models/__init__.py +0 -0
- django_boosted-0.1.1/src/django_boosted/models/urls.py +36 -0
- django_boosted-0.1.1/src/django_boosted/rest_framework/__init__.py +10 -0
- django_boosted-0.1.1/src/django_boosted/rest_framework/metadata.py +25 -0
- django_boosted-0.1.1/src/django_boosted/static/admin_boost/admin_boost.css +153 -0
- django_boosted-0.1.1/src/django_boosted/templates/admin/submit_line.html +10 -0
- django_boosted-0.1.1/src/django_boosted/templates/admin_boost/admin_boost_form.html +45 -0
- django_boosted-0.1.1/src/django_boosted/templates/admin_boost/change_form.html +25 -0
- django_boosted-0.1.1/src/django_boosted/templates/admin_boost/change_list.html +28 -0
- django_boosted-0.1.1/src/django_boosted/templates/admin_boost/confirm.html +33 -0
- django_boosted-0.1.1/src/django_boosted/templates/admin_boost/message.html +26 -0
- django_boosted-0.1.1/src/django_boosted/templatetags/__init__.py +1 -0
- django_boosted-0.1.1/src/django_boosted/templatetags/boosted_tags.py +19 -0
- django_boosted-0.1.1/src/django_boosted.egg-info/PKG-INFO +138 -0
- django_boosted-0.1.1/src/django_boosted.egg-info/SOURCES.txt +44 -0
- django_boosted-0.1.1/src/django_boosted.egg-info/dependency_links.txt +1 -0
- django_boosted-0.1.1/src/django_boosted.egg-info/requires.txt +10 -0
- django_boosted-0.1.1/src/django_boosted.egg-info/top_level.txt +1 -0
- django_boosted-0.1.1/tests/test_views.py +66 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Octolo
|
|
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.
|
|
22
|
+
|
|
23
|
+
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-boosted
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Reusable helpers to register custom Django admin views and object tools.
|
|
5
|
+
Author-email: Octolo <dev@octolo.tech>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/octolo/django-boosted
|
|
8
|
+
Project-URL: Repository, https://github.com/octolo/django-boosted
|
|
9
|
+
Project-URL: Documentation, https://github.com/octolo/django-boosted#readme
|
|
10
|
+
Project-URL: Issues, https://github.com/octolo/django-boosted/issues
|
|
11
|
+
Keywords: django,django-admin,admin-views,admin-tools,django-extensions,admin-customization,python
|
|
12
|
+
Classifier: Framework :: Django
|
|
13
|
+
Classifier: Framework :: Django :: 4.2
|
|
14
|
+
Classifier: Framework :: Django :: 5.0
|
|
15
|
+
Classifier: Intended Audience :: Developers
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
20
|
+
Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
|
|
21
|
+
Requires-Python: >=3.10
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
License-File: LICENSE
|
|
24
|
+
Requires-Dist: Django>=4.2
|
|
25
|
+
Provides-Extra: dev
|
|
26
|
+
Requires-Dist: pytest>=7.4; extra == "dev"
|
|
27
|
+
Requires-Dist: pytest-django>=4.8; extra == "dev"
|
|
28
|
+
Requires-Dist: ruff>=0.7.0; extra == "dev"
|
|
29
|
+
Requires-Dist: black>=24.8; extra == "dev"
|
|
30
|
+
Requires-Dist: bandit>=1.7; extra == "dev"
|
|
31
|
+
Requires-Dist: safety>=3.2; extra == "dev"
|
|
32
|
+
Requires-Dist: pip-audit>=2.7; extra == "dev"
|
|
33
|
+
Dynamic: license-file
|
|
34
|
+
|
|
35
|
+
# django-boosted
|
|
36
|
+
|
|
37
|
+
Lightweight helpers to extend Django’s admin with extra views, custom forms, and the matching UI affordances (object tools, permissions, standard responses).
|
|
38
|
+
|
|
39
|
+
## Features
|
|
40
|
+
|
|
41
|
+
- **`@admin_boost_object_view` decorator** – fetches the target object, checks permissions, and builds the default context before rendering your template.
|
|
42
|
+
- **`AdminBoostMixin`** – registers the custom URLs, protects them with `admin_site.admin_view`, and injects extra object-tool buttons into the change form.
|
|
43
|
+
- **Additional templates** – a change form template that renders the injected buttons plus a simple “Hello” view as a teaching aid.
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pip install django-boosted
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick start
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
# app/admin.py
|
|
55
|
+
from django.contrib import admin
|
|
56
|
+
from django_boosted.mixins import AdminBoostMixin
|
|
57
|
+
from django_boosted.decorators import admin_boost_object_view
|
|
58
|
+
from .models import Client
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class ClientAdmin(AdminBoostMixin, admin.ModelAdmin):
|
|
62
|
+
boost_views = ["hello_view"]
|
|
63
|
+
change_form_template = "admin_boost/change_form.html"
|
|
64
|
+
|
|
65
|
+
@admin_boost_object_view(label="Say hello", template_name="admin_boost/hello.html")
|
|
66
|
+
def hello_view(self, request, obj):
|
|
67
|
+
return {"message": f"Hello {obj}!"}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
admin.site.register(Client, ClientAdmin)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Include the provided templates in your `TEMPLATES["DIRS"]` (or copy them to customize).
|
|
74
|
+
|
|
75
|
+
## Using forms with ForeignKey widgets
|
|
76
|
+
|
|
77
|
+
The decorator can automatically apply admin widgets (`ForeignKeyRawIdWidget` or `AutocompleteSelect`) to your form fields, using the same logic as `ModelAdmin.change_view()`:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
# app/admin.py
|
|
81
|
+
from django import forms
|
|
82
|
+
from django.contrib import admin, messages
|
|
83
|
+
from django.shortcuts import redirect
|
|
84
|
+
from django_boosted.mixins import AdminBoostMixin
|
|
85
|
+
from django_boosted.decorators import admin_boost_object_view
|
|
86
|
+
from .models import Company
|
|
87
|
+
|
|
88
|
+
class SyncFullGroupForm(forms.Form):
|
|
89
|
+
group = forms.ModelChoiceField(queryset=Company.objects.all())
|
|
90
|
+
option = forms.ChoiceField(
|
|
91
|
+
label="sync method",
|
|
92
|
+
choices=[("method1", "Method 1"), ("method2", "Method 2")],
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
class CompanyAdmin(AdminBoostMixin, admin.ModelAdmin):
|
|
96
|
+
boost_views = ["sync_full_group_view"]
|
|
97
|
+
change_form_template = "admin_boost/change_form.html"
|
|
98
|
+
|
|
99
|
+
@admin_boost_object_view(
|
|
100
|
+
label="Sync Full Group",
|
|
101
|
+
template_name="admin/sync_full_group.html",
|
|
102
|
+
form=SyncFullGroupForm,
|
|
103
|
+
raw_id_fields=["group"], # Automatically applies ForeignKeyRawIdWidget
|
|
104
|
+
)
|
|
105
|
+
def sync_full_group_view(self, request, obj, form):
|
|
106
|
+
if request.method == "POST" and form.is_valid():
|
|
107
|
+
# Process form...
|
|
108
|
+
group = form.cleaned_data["group"]
|
|
109
|
+
option = form.cleaned_data["option"]
|
|
110
|
+
# ... your logic ...
|
|
111
|
+
self.message_user(request, "Sync completed", messages.SUCCESS)
|
|
112
|
+
return redirect(obj.admin_change_url)
|
|
113
|
+
return {} # Return additional context if needed
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The decorator handles:
|
|
117
|
+
- Widget application (respects `raw_id_fields` and `autocomplete_fields`)
|
|
118
|
+
- Form validation on POST
|
|
119
|
+
- Adding the form to the template context
|
|
120
|
+
- Backward compatibility (if your view doesn't accept a `form` parameter, it won't be passed)
|
|
121
|
+
|
|
122
|
+
## Development commands
|
|
123
|
+
|
|
124
|
+
Run everything via `./service.py dev <command>` or `python dev.py <command>`:
|
|
125
|
+
|
|
126
|
+
| Command | Description |
|
|
127
|
+
| --- | --- |
|
|
128
|
+
| `./service.py dev install-dev` or `python dev.py install-dev` | create the venv and install the package editable with `dev` extras. |
|
|
129
|
+
| `./service.py dev lint` or `python dev.py lint` | run Ruff + Black in check mode. |
|
|
130
|
+
| `./service.py dev format` or `python dev.py format` | apply Ruff --fix then Black. |
|
|
131
|
+
| `./service.py dev test` or `python dev.py test` | run `pytest` (with `pytest-django`). |
|
|
132
|
+
| `./service.py dev build` or `python dev.py build` | clean then build wheel + sdist. |
|
|
133
|
+
| `./service.py quality security` or `python dev.py security` | Bandit + Safety + pip-audit. |
|
|
134
|
+
| `./service.py dev help` or `python dev.py help` | list all commands. |
|
|
135
|
+
|
|
136
|
+
## License
|
|
137
|
+
|
|
138
|
+
MIT — see the `LICENSE` file. Contributions welcome!
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
# django-boosted
|
|
2
|
+
|
|
3
|
+
Lightweight helpers to extend Django’s admin with extra views, custom forms, and the matching UI affordances (object tools, permissions, standard responses).
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **`@admin_boost_object_view` decorator** – fetches the target object, checks permissions, and builds the default context before rendering your template.
|
|
8
|
+
- **`AdminBoostMixin`** – registers the custom URLs, protects them with `admin_site.admin_view`, and injects extra object-tool buttons into the change form.
|
|
9
|
+
- **Additional templates** – a change form template that renders the injected buttons plus a simple “Hello” view as a teaching aid.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install django-boosted
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick start
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
# app/admin.py
|
|
21
|
+
from django.contrib import admin
|
|
22
|
+
from django_boosted.mixins import AdminBoostMixin
|
|
23
|
+
from django_boosted.decorators import admin_boost_object_view
|
|
24
|
+
from .models import Client
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class ClientAdmin(AdminBoostMixin, admin.ModelAdmin):
|
|
28
|
+
boost_views = ["hello_view"]
|
|
29
|
+
change_form_template = "admin_boost/change_form.html"
|
|
30
|
+
|
|
31
|
+
@admin_boost_object_view(label="Say hello", template_name="admin_boost/hello.html")
|
|
32
|
+
def hello_view(self, request, obj):
|
|
33
|
+
return {"message": f"Hello {obj}!"}
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
admin.site.register(Client, ClientAdmin)
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Include the provided templates in your `TEMPLATES["DIRS"]` (or copy them to customize).
|
|
40
|
+
|
|
41
|
+
## Using forms with ForeignKey widgets
|
|
42
|
+
|
|
43
|
+
The decorator can automatically apply admin widgets (`ForeignKeyRawIdWidget` or `AutocompleteSelect`) to your form fields, using the same logic as `ModelAdmin.change_view()`:
|
|
44
|
+
|
|
45
|
+
```python
|
|
46
|
+
# app/admin.py
|
|
47
|
+
from django import forms
|
|
48
|
+
from django.contrib import admin, messages
|
|
49
|
+
from django.shortcuts import redirect
|
|
50
|
+
from django_boosted.mixins import AdminBoostMixin
|
|
51
|
+
from django_boosted.decorators import admin_boost_object_view
|
|
52
|
+
from .models import Company
|
|
53
|
+
|
|
54
|
+
class SyncFullGroupForm(forms.Form):
|
|
55
|
+
group = forms.ModelChoiceField(queryset=Company.objects.all())
|
|
56
|
+
option = forms.ChoiceField(
|
|
57
|
+
label="sync method",
|
|
58
|
+
choices=[("method1", "Method 1"), ("method2", "Method 2")],
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
class CompanyAdmin(AdminBoostMixin, admin.ModelAdmin):
|
|
62
|
+
boost_views = ["sync_full_group_view"]
|
|
63
|
+
change_form_template = "admin_boost/change_form.html"
|
|
64
|
+
|
|
65
|
+
@admin_boost_object_view(
|
|
66
|
+
label="Sync Full Group",
|
|
67
|
+
template_name="admin/sync_full_group.html",
|
|
68
|
+
form=SyncFullGroupForm,
|
|
69
|
+
raw_id_fields=["group"], # Automatically applies ForeignKeyRawIdWidget
|
|
70
|
+
)
|
|
71
|
+
def sync_full_group_view(self, request, obj, form):
|
|
72
|
+
if request.method == "POST" and form.is_valid():
|
|
73
|
+
# Process form...
|
|
74
|
+
group = form.cleaned_data["group"]
|
|
75
|
+
option = form.cleaned_data["option"]
|
|
76
|
+
# ... your logic ...
|
|
77
|
+
self.message_user(request, "Sync completed", messages.SUCCESS)
|
|
78
|
+
return redirect(obj.admin_change_url)
|
|
79
|
+
return {} # Return additional context if needed
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The decorator handles:
|
|
83
|
+
- Widget application (respects `raw_id_fields` and `autocomplete_fields`)
|
|
84
|
+
- Form validation on POST
|
|
85
|
+
- Adding the form to the template context
|
|
86
|
+
- Backward compatibility (if your view doesn't accept a `form` parameter, it won't be passed)
|
|
87
|
+
|
|
88
|
+
## Development commands
|
|
89
|
+
|
|
90
|
+
Run everything via `./service.py dev <command>` or `python dev.py <command>`:
|
|
91
|
+
|
|
92
|
+
| Command | Description |
|
|
93
|
+
| --- | --- |
|
|
94
|
+
| `./service.py dev install-dev` or `python dev.py install-dev` | create the venv and install the package editable with `dev` extras. |
|
|
95
|
+
| `./service.py dev lint` or `python dev.py lint` | run Ruff + Black in check mode. |
|
|
96
|
+
| `./service.py dev format` or `python dev.py format` | apply Ruff --fix then Black. |
|
|
97
|
+
| `./service.py dev test` or `python dev.py test` | run `pytest` (with `pytest-django`). |
|
|
98
|
+
| `./service.py dev build` or `python dev.py build` | clean then build wheel + sdist. |
|
|
99
|
+
| `./service.py quality security` or `python dev.py security` | Bandit + Safety + pip-audit. |
|
|
100
|
+
| `./service.py dev help` or `python dev.py help` | list all commands. |
|
|
101
|
+
|
|
102
|
+
## License
|
|
103
|
+
|
|
104
|
+
MIT — see the `LICENSE` file. Contributions welcome!
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=68", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "django-boosted"
|
|
7
|
+
version = "0.1.1"
|
|
8
|
+
description = "Reusable helpers to register custom Django admin views and object tools."
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = "MIT"
|
|
12
|
+
license-files = ["LICENSE"]
|
|
13
|
+
authors = [
|
|
14
|
+
{name = "Octolo", email = "dev@octolo.tech"}
|
|
15
|
+
]
|
|
16
|
+
keywords = [
|
|
17
|
+
"django",
|
|
18
|
+
"django-admin",
|
|
19
|
+
"admin-views",
|
|
20
|
+
"admin-tools",
|
|
21
|
+
"django-extensions",
|
|
22
|
+
"admin-customization",
|
|
23
|
+
"python",
|
|
24
|
+
]
|
|
25
|
+
dependencies = [
|
|
26
|
+
"Django>=4.2",
|
|
27
|
+
]
|
|
28
|
+
classifiers = [
|
|
29
|
+
"Framework :: Django",
|
|
30
|
+
"Framework :: Django :: 4.2",
|
|
31
|
+
"Framework :: Django :: 5.0",
|
|
32
|
+
"Intended Audience :: Developers",
|
|
33
|
+
"Programming Language :: Python :: 3",
|
|
34
|
+
"Programming Language :: Python :: 3.11",
|
|
35
|
+
"Programming Language :: Python :: 3.12",
|
|
36
|
+
"Programming Language :: Python :: 3 :: Only",
|
|
37
|
+
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com/octolo/django-boosted"
|
|
42
|
+
Repository = "https://github.com/octolo/django-boosted"
|
|
43
|
+
Documentation = "https://github.com/octolo/django-boosted#readme"
|
|
44
|
+
Issues = "https://github.com/octolo/django-boosted/issues"
|
|
45
|
+
|
|
46
|
+
[project.optional-dependencies]
|
|
47
|
+
dev = [
|
|
48
|
+
"pytest>=7.4",
|
|
49
|
+
"pytest-django>=4.8",
|
|
50
|
+
"ruff>=0.7.0",
|
|
51
|
+
"black>=24.8",
|
|
52
|
+
"bandit>=1.7",
|
|
53
|
+
"safety>=3.2",
|
|
54
|
+
"pip-audit>=2.7",
|
|
55
|
+
]
|
|
56
|
+
|
|
57
|
+
[tool.setuptools]
|
|
58
|
+
package-dir = {"" = "src"}
|
|
59
|
+
|
|
60
|
+
[tool.setuptools.packages.find]
|
|
61
|
+
where = ["src"]
|
|
62
|
+
|
|
63
|
+
[tool.setuptools.package-data]
|
|
64
|
+
django_boosted = ["templates/**/*", "static/**/*"]
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
DJANGO_SETTINGS_MODULE = "tests.settings"
|
|
68
|
+
pythonpath = ["src", "."]
|
|
69
|
+
addopts = "-ra"
|
|
70
|
+
|
|
71
|
+
[tool.black]
|
|
72
|
+
line-length = 88
|
|
73
|
+
target-version = ["py311"]
|
|
74
|
+
|
|
75
|
+
[tool.ruff]
|
|
76
|
+
line-length = 88
|
|
77
|
+
target-version = "py311"
|
|
78
|
+
extend-exclude = ["**/migrations/*"]
|
|
79
|
+
|
|
80
|
+
[tool.ruff.lint]
|
|
81
|
+
select = ["E", "F", "I"]
|
|
82
|
+
|
|
83
|
+
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""Public exports for django-boosted."""
|
|
2
|
+
default_app_config = "django_boosted.apps.DjangoBoostedConfig" # noqa: E402
|
|
3
|
+
|
|
4
|
+
from .admin import AdminBoostModel, AdminBoostFormat # noqa: E402
|
|
5
|
+
from .decorators import admin_boost_action, admin_boost_view # noqa: E402
|
|
6
|
+
|
|
7
|
+
__all__ = [
|
|
8
|
+
"AdminBoostModel",
|
|
9
|
+
"AdminBoostFormat",
|
|
10
|
+
"admin_boost_action",
|
|
11
|
+
"admin_boost_view",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
try:
|
|
15
|
+
from django_boosted.rest_framework.metadata import BoostedRestFrameworkMetadata
|
|
16
|
+
__all__.append("BoostedRestFrameworkMetadata")
|
|
17
|
+
except ImportError:
|
|
18
|
+
pass # rest_framework not installed
|
|
19
|
+
|
|
20
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
from typing import Iterable
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def add_to_fieldset(self, name: str, fields: Iterable[str], **kwargs):
|
|
5
|
+
"""Add fields to a fieldset by name. Create the fieldset if it doesn't exist."""
|
|
6
|
+
if self.fieldsets is None:
|
|
7
|
+
self.fieldsets = []
|
|
8
|
+
|
|
9
|
+
fieldset_dict = None
|
|
10
|
+
|
|
11
|
+
for fieldset in self.fieldsets:
|
|
12
|
+
if fieldset[0] == name:
|
|
13
|
+
fieldset_dict = fieldset[1]
|
|
14
|
+
break
|
|
15
|
+
|
|
16
|
+
if fieldset_dict is None:
|
|
17
|
+
fieldset_dict = {"fields": [],}
|
|
18
|
+
self.fieldsets.append((name, fieldset_dict))
|
|
19
|
+
else:
|
|
20
|
+
if "fields" not in fieldset_dict:
|
|
21
|
+
fieldset_dict["fields"] = []
|
|
22
|
+
elif isinstance(fieldset_dict["fields"], tuple):
|
|
23
|
+
fieldset_dict["fields"] = list(fieldset_dict["fields"])
|
|
24
|
+
|
|
25
|
+
for field in fields:
|
|
26
|
+
if field not in fieldset_dict["fields"]:
|
|
27
|
+
fieldset_dict["fields"].append(field)
|
|
28
|
+
|
|
29
|
+
if kwargs.get("classes"):
|
|
30
|
+
fieldset_dict["classes"] = kwargs.get("classes")
|
|
31
|
+
|
|
32
|
+
def remove_from_fieldset(self, name: str, fields: Iterable[str]):
|
|
33
|
+
"""Remove fields from a fieldset by name."""
|
|
34
|
+
if self.fieldsets is None:
|
|
35
|
+
return
|
|
36
|
+
|
|
37
|
+
for fieldset in self.fieldsets:
|
|
38
|
+
if fieldset[0] == name:
|
|
39
|
+
fieldset_dict = fieldset[1]
|
|
40
|
+
if "fields" in fieldset_dict:
|
|
41
|
+
for field in fields:
|
|
42
|
+
if field in fieldset_dict["fields"]:
|
|
43
|
+
fieldset_dict["fields"].remove(field)
|
|
44
|
+
break
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Formatting utilities for django-boosted."""
|
|
2
|
+
|
|
3
|
+
from django.utils.html import format_html
|
|
4
|
+
from django.templatetags.static import static
|
|
5
|
+
from django.utils.translation import gettext_lazy as _
|
|
6
|
+
|
|
7
|
+
def boolean_icon_html(value):
|
|
8
|
+
"""Return the HTML image (admin icon) for a boolean value."""
|
|
9
|
+
is_ok = value == "✓" if isinstance(value, str) else bool(value)
|
|
10
|
+
icon = "icon-yes.svg" if is_ok else "icon-no.svg"
|
|
11
|
+
return format_html(
|
|
12
|
+
'<img src="{}" alt="{}">',
|
|
13
|
+
static(f"admin/img/{icon}"),
|
|
14
|
+
_("Yes") if is_ok else _("No"),
|
|
15
|
+
)
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def format_label(
|
|
19
|
+
text: str,
|
|
20
|
+
label_type: str = "info",
|
|
21
|
+
size: str | None = None,
|
|
22
|
+
link: str | None = None,
|
|
23
|
+
style: str | None = None,
|
|
24
|
+
) -> str:
|
|
25
|
+
classes = ["boost-label"]
|
|
26
|
+
valid_types = [
|
|
27
|
+
"success",
|
|
28
|
+
"info",
|
|
29
|
+
"warning",
|
|
30
|
+
"danger",
|
|
31
|
+
"primary",
|
|
32
|
+
"secondary",
|
|
33
|
+
"default",
|
|
34
|
+
]
|
|
35
|
+
if label_type.lower() in valid_types:
|
|
36
|
+
classes.append(label_type.lower())
|
|
37
|
+
else:
|
|
38
|
+
classes.append("info")
|
|
39
|
+
if size and size.lower() in ["small", "big"]:
|
|
40
|
+
classes.append(size.lower())
|
|
41
|
+
if link:
|
|
42
|
+
classes.append("link")
|
|
43
|
+
css_class = " ".join(classes)
|
|
44
|
+
tag = "a" if link else "span"
|
|
45
|
+
if link and style:
|
|
46
|
+
return format_html(
|
|
47
|
+
'<{} href="{}" class="{}" style="{}">{}</{}>',
|
|
48
|
+
tag,
|
|
49
|
+
link,
|
|
50
|
+
css_class,
|
|
51
|
+
style,
|
|
52
|
+
text,
|
|
53
|
+
tag,
|
|
54
|
+
)
|
|
55
|
+
if link:
|
|
56
|
+
return format_html(
|
|
57
|
+
'<{} href="{}" class="{}">{}</{}>', tag, link, css_class, text, tag
|
|
58
|
+
)
|
|
59
|
+
if style:
|
|
60
|
+
return format_html(
|
|
61
|
+
'<{} class="{}" style="{}">{}</{}>', tag, css_class, style, text, tag
|
|
62
|
+
)
|
|
63
|
+
return format_html('<{} class="{}">{}</{}>', tag, css_class, text, tag)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
def format_status(
|
|
67
|
+
name: str, status: bool, style: str | None = None, link: str | None = None
|
|
68
|
+
) -> str:
|
|
69
|
+
icon = "✓" if status else "✗"
|
|
70
|
+
status_class = "success" if status else "error"
|
|
71
|
+
tag = "a" if link else "span"
|
|
72
|
+
return format_html(
|
|
73
|
+
'<{} href="{}"><span class="boost-status {}" style="{}">{}</span> '
|
|
74
|
+
'<code>{}</code></{}>',
|
|
75
|
+
tag,
|
|
76
|
+
link,
|
|
77
|
+
status_class,
|
|
78
|
+
style,
|
|
79
|
+
icon,
|
|
80
|
+
name,
|
|
81
|
+
tag,
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def format_with_help_text(html_content: str, help_text: str | None = None) -> str:
|
|
86
|
+
if help_text:
|
|
87
|
+
return format_html(
|
|
88
|
+
'{}<br><small class="help">{}</small>', html_content, help_text
|
|
89
|
+
)
|
|
90
|
+
return html_content
|