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.
@@ -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,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 2.4.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -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.
File without changes