mirror of
https://github.com/jazzband/django-admin2.git
synced 2026-04-24 16:44:47 +00:00
This module is handling list filter creation by inspecting the model of supplied queryset. Contains default mapping for field type filters to our custom form widgets that are rendering links instead of inputs.
104 lines
3.2 KiB
Python
104 lines
3.2 KiB
Python
# -*- coding: utf-8 -*-
|
|
# vim:fenc=utf-8
|
|
|
|
import collections
|
|
import django_filters
|
|
|
|
from itertools import chain
|
|
from django.forms.util import flatatt
|
|
from django.utils.html import format_html
|
|
from django.utils.encoding import force_text
|
|
from django.utils.safestring import mark_safe
|
|
from django.forms import widgets as django_widgets
|
|
from django.utils.translation import ugettext_lazy
|
|
|
|
LINK_TEMPLATE = '<a href=?{0}={1} {2}>{3}</a>'
|
|
|
|
|
|
class ChoicesAsLinksWidget(django_widgets.Select):
|
|
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_text(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', ugettext_lazy('Unknown')),
|
|
('2', ugettext_lazy('Yes')),
|
|
('3', ugettext_lazy('No')),
|
|
]
|
|
|
|
|
|
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.Iterable):
|
|
return queryset.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, basestring):
|
|
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.name] = field_filter
|
|
fields = filterset_dict.keys()
|
|
filterset_dict['Meta'] = type(
|
|
"Meta",
|
|
(),
|
|
{
|
|
'model': queryset.model,
|
|
'fields': fields,
|
|
},
|
|
)
|
|
return type(
|
|
"%sFilterSet" % 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,
|
|
)
|
|
filter_.widget = FILTER_TYPE_TO_WIDGET.get(
|
|
filter_.__class__,
|
|
filter_.widget,
|
|
)
|
|
return filter_
|