kopia lustrzana https://github.com/jedie/PyInventory
Use facets always and auto hide empty item filters
rodzic
29df00e54a
commit
cde20fcb65
|
|
@ -169,7 +169,8 @@ To make a new release, do this:
|
|||
|
||||
[comment]: <> (✂✂✂ auto generated history start ✂✂✂)
|
||||
|
||||
* [**dev**](https://github.com/jedie/PyInventory/compare/v0.23.2...main)
|
||||
* [v0.24.0](https://github.com/jedie/PyInventory/compare/v0.23.2...v0.24.0)
|
||||
* 2025-12-02 - Use facets always and auto hide empty item filters
|
||||
* 2025-12-02 - Update requirements
|
||||
* [v0.23.2](https://github.com/jedie/PyInventory/compare/v0.23.1...v0.23.2)
|
||||
* 2025-11-28 - Fix logo if static path is not just "/static/"
|
||||
|
|
|
|||
|
|
@ -8,5 +8,5 @@
|
|||
"""
|
||||
|
||||
# See https://packaging.python.org/en/latest/specifications/version-specifiers/
|
||||
__version__ = '0.23.2'
|
||||
__version__ = '0.24.0'
|
||||
__author__ = 'Jens Diemer <PyInventory@jensdiemer.de>'
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ class UserInlineMixin:
|
|||
|
||||
|
||||
class BaseUserAdmin(CompareVersionAdmin):
|
||||
show_facets = admin.ShowFacets.ALWAYS
|
||||
form = OnlyUserRelationsModelForm
|
||||
|
||||
def get_changelist(self, request, **kwargs):
|
||||
|
|
@ -102,3 +103,38 @@ class LimitTreeDepthListFilter(admin.SimpleListFilter):
|
|||
if level:
|
||||
level = int(level)
|
||||
return queryset.filter(level__lte=level)
|
||||
|
||||
|
||||
class NoneEmptyRelatedFieldListFilter(admin.RelatedOnlyFieldListFilter):
|
||||
"""
|
||||
Display only choices that results **not** in an empty change list!
|
||||
"""
|
||||
|
||||
def choices(self, changelist):
|
||||
assert changelist.add_facets, f'Facets must be enabled to use {self.__class__.__name__}'
|
||||
|
||||
facet_counts = self.get_facet_queryset(changelist)
|
||||
yield {
|
||||
'selected': self.lookup_val is None and not self.lookup_val_isnull,
|
||||
'query_string': changelist.get_query_string(remove=[self.lookup_kwarg, self.lookup_kwarg_isnull]),
|
||||
'display': _('All'),
|
||||
}
|
||||
for pk_val, val in self.lookup_choices:
|
||||
if count := facet_counts[f'{pk_val}__c']:
|
||||
yield {
|
||||
'selected': self.lookup_val is not None and str(pk_val) in self.lookup_val,
|
||||
'query_string': changelist.get_query_string(
|
||||
{self.lookup_kwarg: pk_val}, [self.lookup_kwarg_isnull]
|
||||
),
|
||||
'display': f'{val} ({count})',
|
||||
}
|
||||
|
||||
if self.include_empty_choice:
|
||||
if count := facet_counts['__c']:
|
||||
yield {
|
||||
'selected': bool(self.lookup_val_isnull),
|
||||
'query_string': changelist.get_query_string(
|
||||
{self.lookup_kwarg_isnull: 'True'}, [self.lookup_kwarg]
|
||||
),
|
||||
'display': f'{self.empty_value_display} ({count})',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ from inventory.admin.base import (
|
|||
BaseImageModelInline,
|
||||
BaseUserAdmin,
|
||||
LimitTreeDepthListFilter,
|
||||
NoneEmptyRelatedFieldListFilter,
|
||||
UserInlineMixin,
|
||||
)
|
||||
from inventory.models import ItemLinkModel, ItemModel
|
||||
|
|
@ -150,10 +151,10 @@ class ItemModelAdmin(ImportExportMixin, SortableAdminBase, BaseUserAdmin):
|
|||
list_filter = (
|
||||
('category', PersistentRelatedFieldListFilter),
|
||||
LimitTreeDepthListFilter,
|
||||
('kind', admin.RelatedOnlyFieldListFilter),
|
||||
('location', admin.RelatedOnlyFieldListFilter),
|
||||
('producer', admin.RelatedOnlyFieldListFilter),
|
||||
('tags', admin.RelatedOnlyFieldListFilter),
|
||||
('kind', NoneEmptyRelatedFieldListFilter),
|
||||
('location', NoneEmptyRelatedFieldListFilter),
|
||||
('producer', NoneEmptyRelatedFieldListFilter),
|
||||
('tags', NoneEmptyRelatedFieldListFilter),
|
||||
)
|
||||
search_fields = ('name', 'description', 'kind__name', 'tags__name')
|
||||
fieldsets = (
|
||||
|
|
|
|||
|
|
@ -50,13 +50,6 @@
|
|||
<h2 id="changelist-filter-header">
|
||||
Filter
|
||||
</h2>
|
||||
<div id="changelist-filter-extra-actions">
|
||||
<h3>
|
||||
<a class="viewlink" href="?_facets=True">
|
||||
Show counts
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<details data-filter-title="Limit tree depth" open="">
|
||||
<summary>
|
||||
By Limit tree depth
|
||||
|
|
@ -69,17 +62,17 @@
|
|||
</li>
|
||||
<li>
|
||||
<a href="?level=1">
|
||||
Only root
|
||||
Only root (0)
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="?level=2">
|
||||
Root + first sub
|
||||
Root + first sub (0)
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="?level=3">
|
||||
Root + first + second sub
|
||||
Root + first + second sub (0)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -265,28 +265,27 @@ class AdminTestCase(HtmlAssertionMixin, TestCase):
|
|||
)
|
||||
with self.assertLogs('inventory.persistent_filters', level=logging.DEBUG) as logs:
|
||||
response = self.client.get(path='/admin/inventory/itemmodel/')
|
||||
|
||||
self.assertEqual(
|
||||
list(response.context_data['cl'].queryset.values_list('name', flat=True)), ['Item 1', 'Item 2']
|
||||
)
|
||||
self.assert_html_parts(
|
||||
response,
|
||||
parts=(
|
||||
'<h1>Select Item to change</h1>',
|
||||
'<a href="/admin/inventory/itemmodel/80dddef9-0000-0000-0000-000000000001/change/">'
|
||||
'<strong>Item 1</strong></a>',
|
||||
'<a href="/admin/inventory/itemmodel/80dddef9-0000-0000-0000-000000000002/change/">'
|
||||
'<strong>Item 2</strong></a>',
|
||||
'<a href="?category__id__exact=1">Category 1</a>',
|
||||
'<a href="?category__id__exact=2">Category 2</a>',
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
list(response.context_data['cl'].queryset.values_list('name', flat=True)), ['Item 1', 'Item 2']
|
||||
)
|
||||
self.assert_html_parts(
|
||||
response,
|
||||
parts=(
|
||||
'<h1>Select Item to change</h1>',
|
||||
'<a href="/admin/inventory/itemmodel/80dddef9-0000-0000-0000-000000000001/change/">'
|
||||
'<strong>Item 1</strong></a>',
|
||||
'<a href="/admin/inventory/itemmodel/80dddef9-0000-0000-0000-000000000002/change/">'
|
||||
'<strong>Item 2</strong></a>',
|
||||
'<a href="?category__id__exact=1">Category 1 (1)</a>',
|
||||
'<a href="?category__id__exact=2">Category 2 (1)</a>',
|
||||
),
|
||||
)
|
||||
self.assertEqual(
|
||||
logs.output,
|
||||
[
|
||||
'DEBUG:inventory.persistent_filters:'
|
||||
"Restore None from 'persistent_parameter_1_inventory_itemmodel_category__id__exact'"
|
||||
],
|
||||
] * 3, # 3 times called because of facet counts :(
|
||||
)
|
||||
|
||||
with self.assertLogs('inventory.persistent_filters', level=logging.DEBUG) as logs:
|
||||
|
|
@ -296,7 +295,7 @@ class AdminTestCase(HtmlAssertionMixin, TestCase):
|
|||
[
|
||||
'DEBUG:inventory.persistent_filters:'
|
||||
"Store '2' to 'persistent_parameter_1_inventory_itemmodel_category__id__exact'"
|
||||
],
|
||||
] * 3, # 3 times called because of facet counts :(
|
||||
)
|
||||
# Only items from category 2:
|
||||
self.assertEqual(list(response.context_data['cl'].queryset.values_list('name', flat=True)), ['Item 2'])
|
||||
|
|
@ -310,7 +309,7 @@ class AdminTestCase(HtmlAssertionMixin, TestCase):
|
|||
"DEBUG:inventory.persistent_filters:"
|
||||
"Restore '2' from 'persistent_parameter_1_inventory_itemmodel_category__id__exact'",
|
||||
"INFO:inventory.persistent_filters:Restore 'category' filter for itemmodel with '2'",
|
||||
],
|
||||
] * 3, # 3 times called because of facet counts :(
|
||||
)
|
||||
# Only items from category 2:
|
||||
self.assertEqual(list(response.context_data['cl'].queryset.values_list('name', flat=True)), ['Item 2'])
|
||||
|
|
@ -323,7 +322,7 @@ class AdminTestCase(HtmlAssertionMixin, TestCase):
|
|||
[
|
||||
'DEBUG:inventory.persistent_filters:'
|
||||
"Store '1' to 'persistent_parameter_1_inventory_itemmodel_category__id__exact'"
|
||||
],
|
||||
] * 3, # 3 times called because of facet counts :(
|
||||
)
|
||||
# Only items from category 1:
|
||||
self.assertEqual(list(response.context_data['cl'].queryset.values_list('name', flat=True)), ['Item 1'])
|
||||
|
|
|
|||
|
|
@ -338,13 +338,6 @@
|
|||
<h2 id="changelist-filter-header">
|
||||
Filter
|
||||
</h2>
|
||||
<div id="changelist-filter-extra-actions">
|
||||
<h3>
|
||||
<a class="viewlink" href="?_facets=True">
|
||||
Show counts
|
||||
</a>
|
||||
</h3>
|
||||
</div>
|
||||
<details data-filter-title="Limit tree depth" open="">
|
||||
<summary>
|
||||
By Limit tree depth
|
||||
|
|
@ -357,17 +350,17 @@
|
|||
</li>
|
||||
<li>
|
||||
<a href="?level=1">
|
||||
Only root
|
||||
Only root (2)
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="?level=2">
|
||||
Root + first sub
|
||||
Root + first sub (6)
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a href="?level=3">
|
||||
Root + first + second sub
|
||||
Root + first + second sub (6)
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
Ładowanie…
Reference in New Issue