django-admin2/djadmin2/filters.py
Michal Kuffa 21e18f9adc Added djadmin2.filters module.
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.
2013-07-06 15:59:55 +02:00

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_