forked from interlegis/sapl
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrispy_layout_mixin.py
173 lines (139 loc) · 5.41 KB
/
crispy_layout_mixin.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
160
161
162
163
164
165
166
167
168
169
170
171
172
173
from math import ceil
from os.path import dirname, join
import rtyaml
from crispy_forms.bootstrap import FormActions
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Div, Fieldset, Layout, Submit
from django.utils import formats
from django.utils.translation import ugettext as _
def heads_and_tails(list_of_lists):
for alist in list_of_lists:
yield alist[0], alist[1:]
def to_column(name_span):
fieldname, span = name_span
return Div(fieldname, css_class='col-md-%d' % span)
def to_row(names_spans):
return Div(*map(to_column, names_spans), css_class='row-fluid')
def to_fieldsets(fields):
for field in fields:
if isinstance(field, list):
legend, row_specs = field[0], field[1:]
rows = [to_row(name_span_list) for name_span_list in row_specs]
yield Fieldset(legend, *rows)
else:
yield field
def form_actions(more=[], save_label=_('Salvar')):
return FormActions(
Submit('salvar', save_label, css_class='pull-right'), *more)
class SaplFormLayout(Layout):
def __init__(self, *fields, label_cancel=_('Cancelar')):
buttons = form_actions(more=[
HTML('<a href="{{ view.cancel_url }}"'
' class="btn btn-inverse">%s</a>' % label_cancel)])
_fields = list(to_fieldsets(fields)) + [to_row([(buttons, 12)])]
super(SaplFormLayout, self).__init__(*_fields)
def get_field_display(obj, fieldname):
field = obj._meta.get_field(fieldname)
verbose_name = str(field.verbose_name)
if field.choices:
value = getattr(obj, 'get_%s_display' % fieldname)()
else:
value = getattr(obj, fieldname)
if value is None:
display = ''
elif 'date' in str(type(value)):
display = formats.date_format(value, "SHORT_DATE_FORMAT")
elif 'bool' in str(type(value)):
display = _('Sim') if value else _('Não')
elif 'ImageFieldFile' in str(type(value)):
if value:
display = '<img src="{}" />'.format(value.url)
else:
display = ''
elif 'FieldFile' in str(type(value)):
if value:
display = '<a href="{}">{}</a>'.format(
value.url,
value.name.split('/')[-1:][0])
else:
display = ''
else:
display = str(value)
return verbose_name, display
class CrispyLayoutFormMixin:
@property
def layout_key(self):
if hasattr(super(CrispyLayoutFormMixin, self), 'layout_key'):
return super(CrispyLayoutFormMixin, self).layout_key
else:
return self.model.__name__
def get_layout(self):
filename = join(
dirname(self.model._meta.app_config.models_module.__file__),
'layouts.yaml')
return read_layout_from_yaml(filename, self.layout_key)
@property
def fields(self):
if hasattr(self, 'form_class') and self.form_class:
return None
else:
'''Returns all fields in the layout'''
return [fieldname for legend_rows in self.get_layout()
for row in legend_rows[1:]
for fieldname, span in row]
def get_form(self, form_class=None):
try:
form = super(CrispyLayoutFormMixin, self).get_form(form_class)
except AttributeError:
# simply return None if there is no get_form on super
pass
else:
form.helper = FormHelper()
form.helper.layout = SaplFormLayout(*self.get_layout())
return form
@property
def list_field_names(self):
'''The list of field names to display on table
This base implementation returns the field names
in the first fieldset of the layout.
'''
rows = self.get_layout()[0][1:]
return [fieldname for row in rows for fieldname, __ in row]
def get_column(self, fieldname, span):
obj = self.get_object()
verbose_name, text = get_field_display(obj, fieldname)
return {
'id': fieldname,
'span': span,
'verbose_name': verbose_name,
'text': text,
}
@property
def layout_display(self):
return [
{'legend': legend,
'rows': [[self.get_column(fieldname, span)
for fieldname, span in row]
for row in rows]
} for legend, rows in heads_and_tails(self.get_layout())]
def read_yaml_from_file(filename):
# TODO cache this at application level
with open(filename, 'r') as yamlfile:
return rtyaml.load(yamlfile)
def read_layout_from_yaml(filename, key):
# TODO cache this at application level
yaml = read_yaml_from_file(filename)
base = yaml[key]
def line_to_namespans(line):
split = [cell.split(':') for cell in line.split()]
namespans = [[s[0], int(s[1]) if len(s) > 1 else 0] for s in split]
remaining = 12 - sum(s for n, s in namespans)
nondefined = [ns for ns in namespans if not ns[1]]
while nondefined:
span = ceil(remaining / len(nondefined))
namespan = nondefined.pop(0)
namespan[1] = span
remaining = remaining - span
return list(map(tuple, namespans))
return [[legend] + [line_to_namespans(l) for l in lines]
for legend, lines in base.items()]