/
widgets.py
159 lines (131 loc) · 5.13 KB
/
widgets.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
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 _
from .compat import format_value
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(format_value(self, v)) for v in value]
value = ','.join(list(value))
return super(CSVWidget, self).render(name, value, attrs)