Skip to content

Commit

Permalink
- Move multiselect to filters file
Browse files Browse the repository at this point in the history
- REmove old multi select
  • Loading branch information
elipe17 committed Aug 21, 2024
1 parent 4bdc0ee commit b1525a5
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 195 deletions.
2 changes: 1 addition & 1 deletion django508/tests/admin/dummies.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from django.contrib import admin
from .multi_select_dropdown import FieldListMultiSelectFilter
from .filters import FieldListMultiSelectFilter


class ReadOnlyDummyMixin(admin.ModelAdmin):
Expand Down
162 changes: 85 additions & 77 deletions django508/tests/admin/filters.py
Original file line number Diff line number Diff line change
@@ -1,85 +1,93 @@
"""Filter classes."""
from django.utils.translation import ugettext_lazy as _
from django.contrib.admin import SimpleListFilter
from ..models import DummyModel


class MultipleChoiceListFilter(SimpleListFilter):
"""Filter class allowing multiple filter options."""

template = "multiselectlistfilter.html"

def lookups(self, request, model_admin):
"""Must be overridden to return a list of tuples (value, verbose value)."""
raise NotImplementedError(
"The MultipleChoiceListFilter.lookups() method must be overridden to "
"return a list of tuples (value, verbose value)."
)
"""File containing filter classes and mixins."""
import urllib.parse
from django.contrib import admin
from django.db.models import Q
from django.utils.translation import gettext_lazy as _
from django.contrib.admin.utils import reverse_field_path
from django.core.exceptions import ValidationError
from django.contrib.admin.options import IncorrectLookupParameters

class MultiSelectMixin:
"""Mixin for multi-select filters."""

def queryset(self, request, queryset):
"""Return queryset based on selected parameters."""
if request.GET.get(self.parameter_name):
kwargs = {self.parameter_name: request.GET[self.parameter_name].split(",")}
queryset = queryset.filter(**kwargs)
return queryset

def value_as_list(self):
"""Convert multiple filter fields to list."""
return self.value().split(",") if self.value() else []
"""Build queryset based on choices."""
params = Q()
for lookup_arg, value in self.used_parameters.items():
params |= Q(**{lookup_arg: value})
try:
return queryset.filter(params)
except (ValueError, ValidationError) as e:
# Fields may raise a ValueError or ValidationError when converting
# the parameters to the correct type.
raise IncorrectLookupParameters(e)

def prepare_querystring_value(self, value):
"""Preparse the query string value."""
# mask all commas or these values will be used
# in a comma-seperated-list as get-parameter
return str(value).replace(',', '%~')


class FieldListMultiSelectFilter(MultiSelectMixin, admin.AllValuesFieldListFilter):
"""Multi select dropdown filter for all kind of fields."""

template = 'multiselectdropdownfilter.html'

def __init__(self, field, request, params, model, model_admin, field_path):
self.lookup_kwarg = '%s__in' % field_path
self.lookup_kwarg_isnull = '%s__isnull' % field_path
lookup_vals = request.GET.get(self.lookup_kwarg)
self.lookup_vals = lookup_vals.split(',') if lookup_vals else list()
self.lookup_val_isnull = request.GET.get(self.lookup_kwarg_isnull)
self.empty_value_display = model_admin.get_empty_value_display()
parent_model, reverse_path = reverse_field_path(model, field_path)
# Obey parent ModelAdmin queryset when deciding which options to show
if model == parent_model:
queryset = model_admin.get_queryset(request)
else:
queryset = parent_model._default_manager.all()
self.lookup_choices = (queryset
.distinct()
.order_by(field.name)
.values_list(field.name, flat=True))
super(admin.AllValuesFieldListFilter, self).__init__(field, request, params, model, model_admin, field_path)

def choices(self, changelist):
"""Overriden choices method."""

def amend_query_string(include=None, exclude=None):
selections = self.value_as_list()
if include and include not in selections:
selections.append(include)
if exclude and exclude in selections:
selections.remove(exclude)
if selections:
csv = ",".join(selections)
return changelist.get_query_string({self.parameter_name: csv})
else:
return changelist.get_query_string(remove=[self.parameter_name])

"""Generate choices."""
add_facets = getattr(changelist, "add_facets", False)
facet_counts = self.get_facet_queryset(changelist) if add_facets else None
query_string = changelist.get_query_string({}, [self.lookup_kwarg, self.lookup_kwarg_isnull])
yield {
"selected": self.value() is None,
"query_string": changelist.get_query_string(remove=[self.parameter_name]),
"display": "All",
"reset": True,
'selected': not self.lookup_vals and self.lookup_val_isnull is None,
'query_string': query_string,
'display': _('All'),
}
for lookup, title in self.lookup_choices:
include_none = False
count = None
empty_title = self.empty_value_display
for i, val in enumerate(self.lookup_choices):
if add_facets:
count = facet_counts[f"{i}__c"]
if val is None:
include_none = True
empty_title = f"{empty_title} ({count})" if add_facets else empty_title
continue

val = str(val)
qval = self.prepare_querystring_value(val)
yield {
"selected": str(lookup) in self.value_as_list(),
"query_string": changelist.get_query_string(
{self.parameter_name: lookup}
),
"include_query_string": amend_query_string(include=str(lookup)),
"exclude_query_string": amend_query_string(exclude=str(lookup)),
"display": title,
'selected': qval in self.lookup_vals,
'query_string': query_string,
"display": f"{val} ({count})" if add_facets else val,
'value': urllib.parse.quote_plus(val),
'key': self.lookup_kwarg,
}
if include_none:
yield {
'selected': bool(self.lookup_val_isnull),
'query_string': query_string,
"display": empty_title,
'value': 'True',
'key': self.lookup_kwarg_isnull,
}


class DummyModelNameFilter(MultipleChoiceListFilter):
"""Simple filter class to show records based on stt."""

title = _("Name")

parameter_name = "name"

def lookups(self, request, model_admin):
"""Available options in dropdown."""
options = list()
objs = DummyModel.objects.all()
for obj in objs:
name = obj.name
options.append((name, name))

return options

def queryset(self, request, queryset):
"""Return queryset of records based on stt code(s)."""
if self.value() is not None and queryset.exists():
names = self.value().split(",")
queryset = queryset.filter(name__in=names)
return queryset
93 changes: 0 additions & 93 deletions django508/tests/admin/multi_select_dropdown.py

This file was deleted.

24 changes: 0 additions & 24 deletions django508/tests/templates/multiselectlistfilter.html

This file was deleted.

0 comments on commit b1525a5

Please sign in to comment.