debian-django-filter/django_filters/widgets.py

158 lines
5.1 KiB
Python

from __future__ import absolute_import
from __future__ import unicode_literals
from collections import Iterable
from itertools import chain
try:
from urllib.parse import urlencode
except:
from urllib import urlencode # noqa
from django import forms
from django.db.models.fields import BLANK_CHOICE_DASH
from django.forms.widgets import flatatt
from django.utils.encoding import force_text
from django.utils.safestring import mark_safe
from django.utils.six import string_types
from django.utils.translation import ugettext as _
class LinkWidget(forms.Widget):
def __init__(self, attrs=None, choices=()):
super(LinkWidget, self).__init__(attrs)
self.choices = choices
def value_from_datadict(self, data, files, name):
value = super(LinkWidget, self).value_from_datadict(data, files, name)
self.data = data
return value
def render(self, name, value, attrs=None, choices=()):
if not hasattr(self, 'data'):
self.data = {}
if value is None:
value = ''
final_attrs = self.build_attrs(attrs)
output = ['<ul%s>' % flatatt(final_attrs)]
options = self.render_options(choices, [value], name)
if options:
output.append(options)
output.append('</ul>')
return mark_safe('\n'.join(output))
def render_options(self, choices, selected_choices, name):
selected_choices = set(force_text(v) for v in selected_choices)
output = []
for option_value, option_label in chain(self.choices, choices):
if isinstance(option_label, (list, tuple)):
for option in option_label:
output.append(
self.render_option(name, selected_choices, *option))
else:
output.append(
self.render_option(name, selected_choices,
option_value, option_label))
return '\n'.join(output)
def render_option(self, name, selected_choices,
option_value, option_label):
option_value = force_text(option_value)
if option_label == BLANK_CHOICE_DASH[0][1]:
option_label = _("All")
data = self.data.copy()
data[name] = option_value
selected = data == self.data or option_value in selected_choices
try:
url = data.urlencode()
except AttributeError:
url = urlencode(data)
return self.option_string() % {
'attrs': selected and ' class="selected"' or '',
'query_string': url,
'label': force_text(option_label)
}
def option_string(self):
return '<li><a%(attrs)s href="?%(query_string)s">%(label)s</a></li>'
class RangeWidget(forms.MultiWidget):
def __init__(self, attrs=None):
widgets = (forms.TextInput, forms.TextInput)
super(RangeWidget, self).__init__(widgets, attrs)
def decompress(self, value):
if value:
return [value.start, value.stop]
return [None, None]
def format_output(self, rendered_widgets):
return '-'.join(rendered_widgets)
class LookupTypeWidget(forms.MultiWidget):
def decompress(self, value):
if value is None:
return [None, None]
return value
class BooleanWidget(forms.Select):
"""Convert true/false values into the internal Python True/False.
This can be used for AJAX queries that pass true/false from JavaScript's
internal types through.
"""
def __init__(self, attrs=None):
choices = (('', _('Unknown')),
('true', _('Yes')),
('false', _('No')))
super(BooleanWidget, self).__init__(attrs, choices)
def render(self, name, value, attrs=None):
try:
value = {
True: 'true',
False: 'false',
'1': 'true',
'0': 'false'
}[value]
except KeyError:
value = ''
return super(BooleanWidget, self).render(name, value, attrs)
def value_from_datadict(self, data, files, name):
value = data.get(name, None)
if isinstance(value, string_types):
value = value.lower()
return {
'1': True,
'0': False,
'true': True,
'false': False,
True: True,
False: False,
}.get(value, None)
class CSVWidget(forms.TextInput):
def _isiterable(self, value):
return isinstance(value, Iterable) and not isinstance(value, string_types)
def value_from_datadict(self, data, files, name):
value = super(CSVWidget, self).value_from_datadict(data, files, name)
if value is not None:
if value == '': # empty value should parse as an empty list
return []
return value.split(',')
return None
def render(self, name, value, attrs=None):
if self._isiterable(value):
value = [force_text(self._format_value(v)) for v in value]
value = ','.join(list(value))
return super(CSVWidget, self).render(name, value, attrs)