mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-03-17 06:30:25 +00:00
139 lines
4.3 KiB
Python
139 lines
4.3 KiB
Python
import collections.abc
|
|
from itertools import chain
|
|
|
|
import django_filters
|
|
from django import forms
|
|
from django.forms import widgets as django_widgets
|
|
from django.forms.utils import flatatt
|
|
from django.utils.encoding import force_str
|
|
from django.utils.html import format_html
|
|
from django.utils.safestring import mark_safe
|
|
from django.utils.translation import gettext_lazy
|
|
|
|
from .utils import type_str
|
|
|
|
LINK_TEMPLATE = '<a href=?{0}={1} {2}>{3}</a>'
|
|
|
|
|
|
class NumericDateFilter(django_filters.DateFilter):
|
|
field_class = forms.IntegerField
|
|
|
|
|
|
class ChoicesAsLinksWidget(django_widgets.Select):
|
|
"""Select form widget that renders links for choices
|
|
instead of select element with options.
|
|
"""
|
|
|
|
def render(self, name, value, attrs=None, choices=()):
|
|
links = []
|
|
for choice_value, choice_label in chain(self.choices, choices):
|
|
links.append(format_html(
|
|
LINK_TEMPLATE,
|
|
name, choice_value, flatatt(attrs), force_str(choice_label),
|
|
))
|
|
return mark_safe(u"<br />".join(links))
|
|
|
|
|
|
class NullBooleanLinksWidget(
|
|
ChoicesAsLinksWidget,
|
|
django_widgets.NullBooleanSelect
|
|
):
|
|
def __init__(self, attrs=None, choices=()):
|
|
super(ChoicesAsLinksWidget, self).__init__(attrs)
|
|
self.choices = [
|
|
('1', gettext_lazy('Unknown')),
|
|
('2', gettext_lazy('Yes')),
|
|
('3', gettext_lazy('No')),
|
|
]
|
|
|
|
|
|
#: Maps `django_filter`'s field filters types to our
|
|
#: custom form widget.
|
|
FILTER_TYPE_TO_WIDGET = {
|
|
django_filters.BooleanFilter: NullBooleanLinksWidget,
|
|
django_filters.ChoiceFilter: ChoicesAsLinksWidget,
|
|
django_filters.ModelChoiceFilter: ChoicesAsLinksWidget,
|
|
}
|
|
|
|
|
|
def build_list_filter(request, model_admin, queryset):
|
|
"""Builds :class:`~django_filters.FilterSet` instance
|
|
for :attr:`djadmin2.ModelAdmin2.Meta.list_filter` option.
|
|
|
|
If :attr:`djadmin2.ModelAdmin2.Meta.list_filter` is not
|
|
sequence, it's considered to be class with interface like
|
|
:class:`django_filters.FilterSet` and its instantiate wit
|
|
`request.GET` and `queryset`.
|
|
"""
|
|
# if ``list_filter`` is not iterable return it right away
|
|
if not isinstance(model_admin.list_filter, collections.abc.Iterable):
|
|
return model_admin.list_filter(
|
|
request.GET,
|
|
queryset=queryset,
|
|
)
|
|
# otherwise build :mod:`django_filters.FilterSet`
|
|
filters = []
|
|
for field_filter in model_admin.list_filter:
|
|
if isinstance(field_filter, str):
|
|
filters.append(get_filter_for_field_name(
|
|
queryset.model,
|
|
field_filter,
|
|
))
|
|
else:
|
|
filters.append(field_filter)
|
|
filterset_dict = {}
|
|
for field_filter in filters:
|
|
filterset_dict[field_filter.field_name] = field_filter
|
|
fields = list(filterset_dict.keys())
|
|
filterset_dict['Meta'] = type(
|
|
type_str('Meta'),
|
|
(),
|
|
{
|
|
'model': queryset.model,
|
|
'fields': fields,
|
|
},
|
|
)
|
|
return type(type_str('%sFilterSet' % queryset.model.__name__), (django_filters.FilterSet, ), filterset_dict,)(request.GET, queryset=queryset)
|
|
|
|
|
|
def build_date_filter(request, model_admin, queryset, field_name="published_date"):
|
|
filterset_dict = {
|
|
"year": NumericDateFilter(
|
|
field_name=field_name,
|
|
lookup_expr="year",
|
|
),
|
|
"month": NumericDateFilter(
|
|
field_name=field_name,
|
|
lookup_expr="month",
|
|
),
|
|
"day": NumericDateFilter(
|
|
field_name=field_name,
|
|
lookup_expr="day",
|
|
)
|
|
}
|
|
filterset_dict["Meta"] = type(
|
|
type_str('Meta'),
|
|
(object, ),
|
|
{"model": queryset.model, "fields": [field_name]},
|
|
)
|
|
|
|
return type(
|
|
type_str('%sDateFilterSet' % queryset.model.__name__),
|
|
(django_filters.FilterSet,),
|
|
filterset_dict,
|
|
)(request.GET, queryset=queryset)
|
|
|
|
|
|
def get_filter_for_field_name(model, field_name):
|
|
"""Returns filter for model field by field name.
|
|
"""
|
|
filter_ = django_filters.FilterSet.filter_for_field(
|
|
django_filters.filterset.get_model_field(model, field_name,),
|
|
field_name,
|
|
)
|
|
print("EXTRA!!!!")
|
|
print(filter_.extra)
|
|
filter_.widget = FILTER_TYPE_TO_WIDGET.get(
|
|
filter_.__class__
|
|
)
|
|
return filter_
|