django-admin-superfilter 0.9.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- django_admin_superfilter-0.9.0.dist-info/METADATA +348 -0
- django_admin_superfilter-0.9.0.dist-info/RECORD +21 -0
- django_admin_superfilter-0.9.0.dist-info/WHEEL +4 -0
- django_admin_superfilter-0.9.0.dist-info/licenses/LICENCE.md +20 -0
- superfilter/__init__.py +0 -0
- superfilter/admin.py +345 -0
- superfilter/apps.py +6 -0
- superfilter/logic.py +376 -0
- superfilter/migrations/0001_savedsuperfilter.py +35 -0
- superfilter/migrations/0002_savedsuperfilter_columns.py +17 -0
- superfilter/migrations/__init__.py +0 -0
- superfilter/models.py +22 -0
- superfilter/static/superfilter/icons/add-filter.svg +1 -0
- superfilter/static/superfilter/icons/columns.svg +1 -0
- superfilter/static/superfilter/icons/reload.svg +1 -0
- superfilter/static/superfilter/icons/trash.svg +1 -0
- superfilter/static/superfilter/icons/x-close.svg +1 -0
- superfilter/static/superfilter/superfilter.css +757 -0
- superfilter/static/superfilter/superfilter.js +990 -0
- superfilter/tests.py +297 -0
- superfilter/views.py +3 -0
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: django-admin-superfilter
|
|
3
|
+
Version: 0.9.0
|
|
4
|
+
Summary: TODO
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENCE.md
|
|
7
|
+
Keywords: django,admin,filter,tools
|
|
8
|
+
Author: Omar BENHAMID
|
|
9
|
+
Author-email: omar.benhamid@smart-gts.com
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Classifier: Framework :: Django
|
|
12
|
+
Classifier: Framework :: Django :: 4
|
|
13
|
+
Classifier: Framework :: Django :: 5
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
16
|
+
Requires-Dist: django (>=4.0)
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# django-admin-superfilter
|
|
20
|
+
|
|
21
|
+
Advanced, modern filtering for Django admin changelists, with saved filters and selectable columns.
|
|
22
|
+
|
|
23
|
+
## Features
|
|
24
|
+
|
|
25
|
+
- Search-bar style filter UI injected into Django admin changelists
|
|
26
|
+
- Type-aware filtering for text, numeric, boolean, choice, date, datetime and relation fields
|
|
27
|
+
- Field path traversal such as `author__email`
|
|
28
|
+
- Saved filters per authenticated user
|
|
29
|
+
- Column selection and ordering persisted with saved filters
|
|
30
|
+
- AJAX-backed relation picker using Django admin Select2 assets
|
|
31
|
+
- Support for custom filter fields via `SuperFilterField`
|
|
32
|
+
- Single JSON query parameter for rules (`sf`) and one for visible columns (`sfc`)
|
|
33
|
+
- Works without templates overrides
|
|
34
|
+
|
|
35
|
+
## Requirements
|
|
36
|
+
|
|
37
|
+
- Python 3.10+
|
|
38
|
+
- Django 4.0+
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
Install the package:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
pip install django-admin-superfilter
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Add the app to `INSTALLED_APPS`:
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
INSTALLED_APPS = [
|
|
52
|
+
# ...
|
|
53
|
+
"superfilter",
|
|
54
|
+
]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Run migrations:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
python manage.py migrate
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Quick start
|
|
64
|
+
|
|
65
|
+
```python
|
|
66
|
+
from django.contrib import admin
|
|
67
|
+
from superfilter.admin import SuperFilterAdminMixin
|
|
68
|
+
|
|
69
|
+
from .models import Bird
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
@admin.register(Bird)
|
|
73
|
+
class BirdAdmin(SuperFilterAdminMixin, admin.ModelAdmin):
|
|
74
|
+
list_display = ("species", "location", "count")
|
|
75
|
+
search_fields = ("species",)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Important:
|
|
79
|
+
|
|
80
|
+
- Put `SuperFilterAdminMixin` before `admin.ModelAdmin` in the MRO.
|
|
81
|
+
- By default, filterable fields come from `list_display`.
|
|
82
|
+
- Non-model entries in `list_display` are ignored.
|
|
83
|
+
- Traversed model fields like `location__city__name` are supported.
|
|
84
|
+
|
|
85
|
+
## What appears in the UI
|
|
86
|
+
|
|
87
|
+
The package adds a search-bar-like control above the changelist with:
|
|
88
|
+
|
|
89
|
+
- an add-filter button
|
|
90
|
+
- filter badges for current rules
|
|
91
|
+
- an Apply button
|
|
92
|
+
- a split menu with Save
|
|
93
|
+
- a Reset button
|
|
94
|
+
- a Columns toggle button
|
|
95
|
+
- a collapsible column chooser
|
|
96
|
+
- saved filter chips
|
|
97
|
+
|
|
98
|
+
Saved filters store both:
|
|
99
|
+
|
|
100
|
+
- the active filter rules
|
|
101
|
+
- the selected column list and order
|
|
102
|
+
|
|
103
|
+
## Supported field kinds and operators
|
|
104
|
+
|
|
105
|
+
### All fields
|
|
106
|
+
|
|
107
|
+
- `set`
|
|
108
|
+
- `not_set`
|
|
109
|
+
|
|
110
|
+
### Text-like fields
|
|
111
|
+
|
|
112
|
+
Text-like fields include `CharField`, `TextField`, `EmailField`, `SlugField`, `URLField`, `UUIDField`.
|
|
113
|
+
|
|
114
|
+
Operators:
|
|
115
|
+
|
|
116
|
+
- `set`
|
|
117
|
+
- `not_set`
|
|
118
|
+
- `eq`
|
|
119
|
+
- `neq`
|
|
120
|
+
- `contains`
|
|
121
|
+
- `not_contains`
|
|
122
|
+
- `in`
|
|
123
|
+
- `not_in`
|
|
124
|
+
|
|
125
|
+
### Numeric fields
|
|
126
|
+
|
|
127
|
+
Operators:
|
|
128
|
+
|
|
129
|
+
- `set`
|
|
130
|
+
- `not_set`
|
|
131
|
+
- `eq`
|
|
132
|
+
- `neq`
|
|
133
|
+
- `gt`
|
|
134
|
+
- `lt`
|
|
135
|
+
- `gte`
|
|
136
|
+
- `lte`
|
|
137
|
+
|
|
138
|
+
### Boolean fields
|
|
139
|
+
|
|
140
|
+
Operators:
|
|
141
|
+
|
|
142
|
+
- `set`
|
|
143
|
+
- `not_set`
|
|
144
|
+
- `true`
|
|
145
|
+
- `false`
|
|
146
|
+
|
|
147
|
+
### Choice fields
|
|
148
|
+
|
|
149
|
+
Operators:
|
|
150
|
+
|
|
151
|
+
- `set`
|
|
152
|
+
- `not_set`
|
|
153
|
+
- `in`
|
|
154
|
+
- `not_in`
|
|
155
|
+
|
|
156
|
+
### Foreign key / relation fields
|
|
157
|
+
|
|
158
|
+
Operators:
|
|
159
|
+
|
|
160
|
+
- `set`
|
|
161
|
+
- `not_set`
|
|
162
|
+
- `in`
|
|
163
|
+
- `not_in`
|
|
164
|
+
|
|
165
|
+
### Date and datetime fields
|
|
166
|
+
|
|
167
|
+
Operators:
|
|
168
|
+
|
|
169
|
+
- `set`
|
|
170
|
+
- `not_set`
|
|
171
|
+
- `eq`
|
|
172
|
+
- `before`
|
|
173
|
+
- `after`
|
|
174
|
+
- `between`
|
|
175
|
+
|
|
176
|
+
## Semantics
|
|
177
|
+
|
|
178
|
+
- `set` means the field is considered populated
|
|
179
|
+
- `not_set` means the field is empty
|
|
180
|
+
- For text fields, empty means `NULL` or empty string
|
|
181
|
+
- For boolean fields, `set` / `not_set` only target `NULL` vs non-`NULL`
|
|
182
|
+
- `contains` uses `icontains`
|
|
183
|
+
- `not_contains` negates `icontains`
|
|
184
|
+
- `between` on date/datetime expects exactly two values
|
|
185
|
+
- Relation filters use selected related object primary keys
|
|
186
|
+
|
|
187
|
+
## Configuration
|
|
188
|
+
|
|
189
|
+
`SuperFilterAdminMixin` exposes a few attributes:
|
|
190
|
+
|
|
191
|
+
- `superfilter_param_name = "sf"`
|
|
192
|
+
- `superfilter_columns_param_name = "sfc"`
|
|
193
|
+
- `superfilter_fields = None`
|
|
194
|
+
- `superfilter_page_size = 25`
|
|
195
|
+
- `superfilter_all_limit = 2000`
|
|
196
|
+
|
|
197
|
+
Example:
|
|
198
|
+
|
|
199
|
+
```python
|
|
200
|
+
class BirdAdmin(SuperFilterAdminMixin, admin.ModelAdmin):
|
|
201
|
+
list_display = ("species", "location", "count")
|
|
202
|
+
superfilter_page_size = 50
|
|
203
|
+
superfilter_all_limit = 5000
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## Restricting filterable fields
|
|
207
|
+
|
|
208
|
+
By default, filterable fields are taken from `list_display`.
|
|
209
|
+
|
|
210
|
+
To expose a different set of fields, use `superfilter_fields`:
|
|
211
|
+
|
|
212
|
+
```python
|
|
213
|
+
class BirdAdmin(SuperFilterAdminMixin, admin.ModelAdmin):
|
|
214
|
+
list_display = ("species", "location", "count")
|
|
215
|
+
superfilter_fields = ("species", "count", "location__city")
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
This only affects filterable fields. Column selection still uses `list_display`.
|
|
219
|
+
|
|
220
|
+
## Custom filter fields
|
|
221
|
+
|
|
222
|
+
You can plug in custom fields that do not map directly to a Django model field.
|
|
223
|
+
|
|
224
|
+
Create a subclass of `SuperFilterField`:
|
|
225
|
+
|
|
226
|
+
```python
|
|
227
|
+
from django.db.models import Q
|
|
228
|
+
from superfilter.logic import SuperFilterField
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
class HasLargeCountField(SuperFilterField):
|
|
232
|
+
path = "has_large_count"
|
|
233
|
+
label = "Large count"
|
|
234
|
+
kind = "choice"
|
|
235
|
+
choices = [
|
|
236
|
+
{"value": "yes", "label": "Yes"},
|
|
237
|
+
{"value": "no", "label": "No"},
|
|
238
|
+
]
|
|
239
|
+
|
|
240
|
+
def apply_rule(self, queryset, rule):
|
|
241
|
+
values = set(rule.get("value") or [])
|
|
242
|
+
if "yes" in values and "no" not in values:
|
|
243
|
+
return queryset.filter(count__gte=100)
|
|
244
|
+
if "no" in values and "yes" not in values:
|
|
245
|
+
return queryset.filter(count__lt=100)
|
|
246
|
+
return queryset
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
Register it in `superfilter_fields`:
|
|
250
|
+
|
|
251
|
+
```python
|
|
252
|
+
class BirdAdmin(SuperFilterAdminMixin, admin.ModelAdmin):
|
|
253
|
+
list_display = ("species", "location", "count")
|
|
254
|
+
superfilter_fields = ("species", HasLargeCountField)
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
## Saved filters
|
|
258
|
+
|
|
259
|
+
Saved filters are stored in the `SavedSuperFilter` model and are scoped by:
|
|
260
|
+
|
|
261
|
+
- user
|
|
262
|
+
- app label
|
|
263
|
+
- model name
|
|
264
|
+
- saved filter name
|
|
265
|
+
|
|
266
|
+
Notes:
|
|
267
|
+
|
|
268
|
+
- saving requires an authenticated user
|
|
269
|
+
- saved filters are private to the user
|
|
270
|
+
- the latest saved filter with column settings is used as fallback when `sfc` is absent from the querystring
|
|
271
|
+
|
|
272
|
+
## URL format
|
|
273
|
+
|
|
274
|
+
Rules are sent in the `sf` query parameter as JSON:
|
|
275
|
+
|
|
276
|
+
```json
|
|
277
|
+
[
|
|
278
|
+
{"field": "species", "op": "contains", "value": "owl"},
|
|
279
|
+
{"field": "location", "op": "in", "value": [1, 2]},
|
|
280
|
+
{"field": "count", "op": "gte", "value": 10}
|
|
281
|
+
]
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
Columns are sent in the `sfc` query parameter as JSON:
|
|
285
|
+
|
|
286
|
+
```json
|
|
287
|
+
["location", "species", "count"]
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Relation option loading
|
|
291
|
+
|
|
292
|
+
For relation filters, the package exposes an admin endpoint that:
|
|
293
|
+
|
|
294
|
+
- reuses the related admin's `get_search_results()` when available
|
|
295
|
+
- otherwise falls back to searching up to three text fields
|
|
296
|
+
- otherwise falls back to PK search for numeric terms
|
|
297
|
+
|
|
298
|
+
## Static assets
|
|
299
|
+
|
|
300
|
+
The mixin injects:
|
|
301
|
+
|
|
302
|
+
- `admin/css/vendor/select2/select2.min.css`
|
|
303
|
+
- `admin/js/vendor/select2/select2.full.min.js`
|
|
304
|
+
- `superfilter/superfilter.css`
|
|
305
|
+
- `superfilter/superfilter.js`
|
|
306
|
+
|
|
307
|
+
No custom template override is required.
|
|
308
|
+
|
|
309
|
+
## Limitations
|
|
310
|
+
|
|
311
|
+
- Filtering ignores callable/computed `list_display` entries unless implemented as `SuperFilterField`
|
|
312
|
+
- Column selection only works on entries present in `list_display`
|
|
313
|
+
- Saved filters depend on migrations for the `superfilter` app being applied
|
|
314
|
+
- The package ships with admin-focused frontend assets and is not intended for non-admin pages
|
|
315
|
+
|
|
316
|
+
## Example project
|
|
317
|
+
|
|
318
|
+
A runnable sample project is available in:
|
|
319
|
+
|
|
320
|
+
- `examples/sampleapp/`
|
|
321
|
+
|
|
322
|
+
Run it with:
|
|
323
|
+
|
|
324
|
+
```bash
|
|
325
|
+
cd examples/sampleapp
|
|
326
|
+
python manage.py migrate
|
|
327
|
+
python manage.py runserver
|
|
328
|
+
```
|
|
329
|
+
|
|
330
|
+
## Development
|
|
331
|
+
|
|
332
|
+
Run tests from the repository root:
|
|
333
|
+
|
|
334
|
+
```bash
|
|
335
|
+
python manage.py test superfilter
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Or use the sample project:
|
|
339
|
+
|
|
340
|
+
```bash
|
|
341
|
+
cd examples/sampleapp
|
|
342
|
+
python manage.py test
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
## License
|
|
346
|
+
|
|
347
|
+
MIT. See `LICENCE.md`.
|
|
348
|
+
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
superfilter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
|
+
superfilter/admin.py,sha256=vX6DEb4nocJuYOf6FkS7gRLY85l5V9fQJ35edVb6S6I,13957
|
|
3
|
+
superfilter/apps.py,sha256=mJd5sqbZSUue9IbeUfJx5cy9J0JSAV3fWvP0nEkhSbQ,160
|
|
4
|
+
superfilter/logic.py,sha256=vDs_HpWStY_3xoQcGJTUaVDP1TZj75rMYBYksFo_HhI,12525
|
|
5
|
+
superfilter/migrations/0001_savedsuperfilter.py,sha256=9yxuI0oF-JERgZLRuBMfou7GhLd7FUG0SBSEj1kzYOE,1405
|
|
6
|
+
superfilter/migrations/0002_savedsuperfilter_columns.py,sha256=rTYli7O7pT6S1-ltTRcIOxxYXt72jqYap6L794a1KQQ,377
|
|
7
|
+
superfilter/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
8
|
+
superfilter/models.py,sha256=7p5vP2uhnp6ISelDRtCyQ53P4Umr1v4AFMx_GYH2-MI,872
|
|
9
|
+
superfilter/static/superfilter/icons/add-filter.svg,sha256=Jb7wv7hxPFvmsfzEPBj8RptXCd6bMcWxUGiMLWwhEuw,446
|
|
10
|
+
superfilter/static/superfilter/icons/columns.svg,sha256=ifFgsRIZjPOzadPJEZX1jgatCK1_L8pswcm7rm66V8U,477
|
|
11
|
+
superfilter/static/superfilter/icons/reload.svg,sha256=ET_4GTe2VrTAmbLlLIQAufcjKfbQ2N9lNOP1UbUUi3o,626
|
|
12
|
+
superfilter/static/superfilter/icons/trash.svg,sha256=EdXnbkJKKDInWA7E72_ddoKLfNrCRbTrPBQzUugzoe8,726
|
|
13
|
+
superfilter/static/superfilter/icons/x-close.svg,sha256=ONCzp_yianACIill68DzVSchWvSzoKJmJd5AhLbnH7s,511
|
|
14
|
+
superfilter/static/superfilter/superfilter.css,sha256=mAfCjvWyqIprttQqWyUxDfus_bZFDGImPqQTIqrRmbA,16319
|
|
15
|
+
superfilter/static/superfilter/superfilter.js,sha256=W_Wr9K1Cmxz4DkJha4ekuisIJvEhJroLy_ioP5JrP_E,48983
|
|
16
|
+
superfilter/tests.py,sha256=kCGiwY5rwXtggv-eopH9oGZgf3WF9-m2aD67lM8X_Zk,12681
|
|
17
|
+
superfilter/views.py,sha256=u0FhL7RT5byf5IlcnZEMrcH2TOnQkdfRQU2SjtA26m0,66
|
|
18
|
+
django_admin_superfilter-0.9.0.dist-info/licenses/LICENCE.md,sha256=6XF4HG1ozz-d48cvGtVphfLR6hYYr8cLQcP-KH4ft74,1089
|
|
19
|
+
django_admin_superfilter-0.9.0.dist-info/METADATA,sha256=aNEX0SCLbH65zlEI35uyO-9kX8wjlVv51ManVk4DRFs,7441
|
|
20
|
+
django_admin_superfilter-0.9.0.dist-info/WHEEL,sha256=EGEvSphFYqXKs23-kQBeyNoJP1nrT8ZJKQoi5p5DYL8,88
|
|
21
|
+
django_admin_superfilter-0.9.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# MIT LICENCE
|
|
2
|
+
Copyright (c) 2025 Omar BENHAMID
|
|
3
|
+
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
superfilter/__init__.py
ADDED
|
File without changes
|